Kieran's Programming Beginner Questions

Started by kieranmillar, November 15, 2017, 08:54:21 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

kieranmillar

With the development of Lem3edit as a learning experience for me into serious programming, I predict lots and lots of embarrassing questions about C++ or git. So I thought I'd make a thread for them in the hope that the Lemmings community's resident programmers can offer some help.

My first question is about general structuring of code and classes.

Lem3edit has an editor class. This class contains everything to do with the actual level editor part of the program (imagine one day there will be other parts of the program like a main menu etc.).

The editor class creates instances of other classes and stores them in member variables. So for example, there's a Style class that stores all of the graphics for that style (Classic, Egypt or Shadow), and a Level class that stores all of the terrain pieces and objects that make up the level itself.

I'm looking to add a proper interface for adding objects and terrain to the level, and so want to split the interface in two, the "canvas" which is the main part of the screen, displaying the terrain and objects in the level and where you move them etc., and a "bar" at the bottom of the screen which contains a scrollable list of all of the terrain pieces etc. A lot like lgl2. It makes sense to me to make these separate classes, and have the editor create instances of them.

This means I now have an Editor class that has the following "Inner" classes:

  • Style
  • Level
  • Canvas
  • Bar

My problem is what to do when one of these inner classes needs to access another inner class? Clearly Canvas and Bar are both going to need access to the terrain piece graphics stored in Style, as an example. What's the best way to handle this?

My first thought is to always pass a pointer to the Editor instance when creating these member class instances. That way I can just point back to the Editor and then dive down from there. Is that the correct thing to do. Referring back to the top of the nest feels wrong to me, but maybe I'm just confusing this with the concept of inheritance?

I hope this all made sense.

kieranmillar

OK so I think I've gotten to the bottom of this. Ultimately I suppose there is little wrong with referencing another "module" of an object by pointing back to the top module and then diving down, so the structure of my program is probably fine.

The exceptionally stupid idea here was, instead of passing a pointer to the top module when creating the nested object and then storing it locally, I would just pass it around in the module's functions again and again so I could access it. Obviously this is really stupid and is why I was starting to have tons of pointers in all my function parameters.

I need more sleep right now, I think.

Simon

Dependency injection sounds reasonable, but passing the entire Editor* looks like too much. Consider to pass only what the using class needs. E.g., the bar needs access to the style, but not to the terrain pieces already within the level.

Whether to pass the dependency anew in each call, or whether to store the pointer permanently, has no catch-all answer.

-- Simon

Colorful Arty

Indeed, make sure to weigh all of the possible implementations, and to choose the one that will be efficient either in speed or space, whichever is more prudent.
My Youtube channel where I let's play games with family-friendly commentary:
https://www.youtube.com/channel/UCiRPZ5j87ft_clSRLFCESQA

My Twitch channel: https://www.twitch.tv/colorfularty

My levelpack: SubLems
For New formats NeoLemmix: https://www.lemmingsforums.net/index.php?topic=4942.0
For Old formats NeoLemmix: http://www.lemmingsforums.net/index.php?topic=2787.0
For SuperLemmini: http://www.lemmingsforums.net/index.php?topic=2704.0

My levelpack: ArtLems
For New formats NeoLemmix: https://www.lemmingsforums.net/index.php?topic=4583.0

kieranmillar

Thanks guys. It's all starting to make more sense and I'm slowly getting somewhere.

Slowly working my way through all this pointer and constructor stuff. I understand pointers, but taking a while to get used to the specifics of C++'s language here. But I see the light at the end of the tunnel, just gotta keeping plowing through until it's second nature.

nin10doadict

I remember using C++ in my computer science classes in college. I hated it and my code was terrible; I basically brute-forced everything. :8(): Coding just isn't my thing. Hopefully you'll have more success with it than I have.

Colorful Arty

Well, I find C/C++ particularly annoying languages to work with due to all of the low-level things you need to include in your code like memory management and pointers. And of course, the two words every computer scientist dreads most of all...

Segmentation Fault
My Youtube channel where I let's play games with family-friendly commentary:
https://www.youtube.com/channel/UCiRPZ5j87ft_clSRLFCESQA

My Twitch channel: https://www.twitch.tv/colorfularty

My levelpack: SubLems
For New formats NeoLemmix: https://www.lemmingsforums.net/index.php?topic=4942.0
For Old formats NeoLemmix: http://www.lemmingsforums.net/index.php?topic=2787.0
For SuperLemmini: http://www.lemmingsforums.net/index.php?topic=2704.0

My levelpack: ArtLems
For New formats NeoLemmix: https://www.lemmingsforums.net/index.php?topic=4583.0

kieranmillar

Today I had an awful lot of trouble with circular declarations, largely because of the nonsense errors that Visual Studio threw out meant it took me a while to understand what was even going wrong. I think I now know how to fix it, but it's late so will have to wait for next time.

I look forward to the chaos from my decision to try to slghtly restructure things ending, and I can get back to implementing cool stuff and things.

Simon

Nested classes

Nested class is a class declared inside another class:

class Editor {
    int x;
    class Nested {
        int y;
    };
};


Nested classes are not inheritance. Inheritance would be wrong in the OP's design, an Editor cannot be used where a Style is required, nor can a Style be used where an editor is required.

C++ nested classes are like static inner classes in D or Java. C++ nested classes cannot access any outside object of the enveloping class. You can have an Editor::Nested and no Editor, that will work perfectly fine, it has one field Editor::Nested::y. There is no pointer to any Editor within the Editor::Nested, and there is no Editor::Nested::x because that's a field of Editor, an unrelated class.

The point of nesting is naming and possibly implementation hiding. Within Editor, the Nested is called Nested, whereas outside of the Editor, the class is called Editor::Nested. You can declare class Nested private with the usual effects: The symbol is not visible outside of Editor.

I would not use nested classes because most of the application is an editor, therefore Editor::Nested doesn't gain much over naming it Nested. But the design is not wrong either.

Everything else

The design issue from OP arises in any object-oriented language, not merely in C++.

Yes, your code in C++ gets longer than in most other languages. You can hide the allocation in wrapper structs or the standard library's unique/shared/weak pointers. But you choose C++ in the first place only when you want the low level, and have ruled out D/Rust/Crystal/... for whatever reason. Learning some C++ can't hurt either, the language is really common.

QuoteI basically brute-forced everything.

The type system is your best friend, do not betray it. :lix-scared: But yes, it requires some proficiency to become useful in the first place.

-- Simon

Colorful Arty

This is why I like Python, because it is typeless you are given much more freedom and power in your code.
My Youtube channel where I let's play games with family-friendly commentary:
https://www.youtube.com/channel/UCiRPZ5j87ft_clSRLFCESQA

My Twitch channel: https://www.twitch.tv/colorfularty

My levelpack: SubLems
For New formats NeoLemmix: https://www.lemmingsforums.net/index.php?topic=4942.0
For Old formats NeoLemmix: http://www.lemmingsforums.net/index.php?topic=2787.0
For SuperLemmini: http://www.lemmingsforums.net/index.php?topic=2704.0

My levelpack: ArtLems
For New formats NeoLemmix: https://www.lemmingsforums.net/index.php?topic=4583.0

geoo

Well, in python you don't have to declare your types, but that makes your Type Errors appear at run time instead of compile time. So this kind of error is harder to debug in Python than in C++, they might slip under the radar more easily.
That said, I do like Python a lot as you can do many things very easily and compactly, and comparatively C++ feels like a pain. Though I think the lack of type-safety is one of the reasons python is not that popular for big projects that have to run reliably.

In C++, since C++11 you also have the auto statement if you're too lazy to infer the type yourself. I'm not sure that's considered good style though.

kieranmillar

Thanks guys for all the interesting comments. I picked C++ or this project for the simple reason that Mindless also wrote it in C++! But, I think C++ is useful to know. Having to be so careful and specific is helping me learn a lot, even if it can be slow going sometimes.

Simon, I looked into Nested classes but agree it does not feel like the way to go here. Each class is defined separately.

A good idea about using a struct to hold my pointers to the other objects, that makes a lot of sense.

kieranmillar

A question for slightly more experienced C++ers.

There are 3 things left in my lem3edit project that require some external library, ideally all of which will be cross platform, a standard file browser dialog for opening and saving files, a way to execute another program (in this case DosBox), and moving and renaming files.

I like that so far lem3edit is quite simple and involves only a small number of small libraries to set everything up. All of the above I believe can be achieved by adding something like QT or wxwidgets to the project, but I'm sort of trying to avoid using these as they look like quite large libraries. Maybe that's a mistake and I should just use them?

What do people think? Any advice from seasoned hobby program makers?

For file dialogs Tiny File Dialogs (https://sourceforge.net/projects/tinyfiledialogs/ ) looks decent. But what for the other two? I believe C++ now incorporates the file manipulation features from C++ Boost library so nothing needed there possibly. As for executing another program, C++ has the System command, but everywhere online seems to recommend avoiding that, say it's a potential security hole and resource intensive, but fails to ever explain how something like Boost.Process is any better in this regard. Maybe using System is fine given lem3edit is just a simply hobby program, but I'd like to abide by best practice if possible. Seems a shame to add the whole Boost system just for this one function though.

Simon

For GUI, pick one that you like and use it. It's okay to ask other developers to install it. The larger, more well-known toolkits should be readily packaged by Linux distributions; on Windows, I can't tell what's easiest to use.

Moving and renaming files, if the GUI toolkit doesn't offer that, you can probably use Boost... though I don't know whether you can rely on only a part of Boost, or whether you have to rely on the entire package. I haven't ever used it. But very popular.

Executing another program, again, I haven't done it in a serious project. Rely on the wisdom of the internet. I'd be interested in why Boost.Process is better.

-- Simon

kieranmillar

Thanks for the response Simon, I think I'll go with tiny file dialogs and Boost and see how it goes. I'm not sure how much of Boost you need to install, at a glance it looks like it's modular to some extent (outside of some base and core modules).