Constructors, Factory Methods and Destructor Questions

Started by
15 comments, last by Servant of the Lord 9 years, 5 months ago

Another downside to be aware of though, is when you use a complex constructor (and no default constructor), you're limiting your class from being usable in some places, e.g. std::vector will no longer work (but std::vector will).

*>
That's not true. The only requirement for use in std::vector is that a type is assignable and copyable (and in modern C++, those restrictions are relaxed to simply movable), neither of which requires a default constructor.


Some containers do have member functions that use default-constructed values as default-parameters.

std::vector<MyType> myVector(50), for example. Default-constructs 50 elements. You have to call std::vector<MyType> myVector(50, <some value to copy from>) if you don't have a default constructor.

And if you don't have a default constructor OR a copy-constructor, then you can't call resize() (or the resizing std::vector constructors). In that case, you'll have to just call push_back(std::move(value)) or emplace_back(construction params), probably after calling reserve() first.

Not show-stopping, but something you have to work around. It's not very convenient when some of the convenience functions are unusable. smile.png

Advertisement

Small point of order - modern C++ lets you delete functions with "=delete". This implements "non-copyable" in a much cleaner way, and one that the compiler can catch at compile time, rather then link time.

You get a compile time error with the older method as well, because the (unlinkable) functions are private.

What does C# have that makes composition easier than in say C++?

I wasn't saying that C# is better than C++ in this regard -- I mentioned C#'s support for composition because the OP stated that C# seems to thrive on inheritance.
...but anyway, it depends which C++ you're talking about smile.png
C++ now has first-class-functions (via the standard library, not a language feature) and lambdas, but C# had them long before they were standardized in the C++ world.
Before C++ 11, you had to either use boost::function and/or roll your own lambdas/closures using a rediculous amount of boilerplate code (usually a struct with a constructor that captures the locals explicitly, and an operator() so it acts like a functor).
C#'s generics aren't equal to C++'s templates. In a lot of ways, templates are way more powerful... but generics also have some interesting features similar to the proposed C++ 'concepts' feature. Plus C#'s compilation system is modern, letting you actually use generics without worrying about "moving code into a header file", ruining compile times, ruining inter-system coupling, etc...
Both generics and C#'s actual duck typing support can be used to reduce the amount of boilerplate 'adapter pattern' style code that's required when gluing self-contained components into larger systems.

Small point of order - modern C++ lets you delete functions with "=delete". This implements "non-copyable" in a much cleaner way, and one that the compiler can catch at compile time, rather then link time.

You get a compile time error with the older method as well, because the (unlinkable) functions are private.


Unless the code calling the copy constructor/operator = is in your base class. (Not too likely with your inheritance method - more likely if you want to avoid inheritance)

It's debatable as to whether a "cannot call private method" or "cannot call deleted method" is a clearer compiler error smile.png

I personally prefer the =delete method simply because it "reads" better to me. "Hey guys, here's this function - or function overload - that I know might be called, but I want to specifically make sure it isn't"

It's also useful for when you, say, want a function to be able to accept some types of arguments but not others (even though the compiler would silently cast for you).

I've been scraping with it being the Thanksgiving holiday and all. Here's a little bit of a response I have so far:


A common use of this is with GUI widget libraries - because you often want to write run-time* generic "for every child widget" code, since many 'widgets' contain children that also are widgets but without knowing what kind of widgets the children are.

*If you want compile-time generic functionality, you use templates - another very powerful tool.

C++ has a design goal: "Don't pay for what you don't need", that makes the language lightning fast. So when I say virtual inheritance "costs" extra, I don't want to give the wrong impression that virtual inheritance is slow. It's not. It's still lightning fast, but slightly less lightning fast than not using virtual. Other languages often opt-in to pay the same costs 100% of the time, whereas C++ says, "Only pay for it when you actually want it".

I agree. I think it makes sense that there will be systems, such as the Widget system for menus, to have a base class that everything inherits from. That way, a controller class can iterate through everything, and operate on the objects generically. This type of example heavily suggests the need for virtual methods that could be overridden by sub-classes to do their specific tasks. Now, what if I wanted to build a system where everything had to inherit from something, but there was no need for virtual members? All sub-classes have to inherit from the base class that's being treated as an interface. Would that generate a vtable for each sub-class, or is that compiler-specific?


I would say that in every OO language, inheritance should be use sparingly, but unfortunately many people suffer from inheritance-addiction.

I'm a recovering abuser of inheritancelaugh.png I'm starting to realize that templates are a good answer to some cases. I'm under the impression that templates still maintain the performance you'd lose by creating a vtable for sub-classes at the cost of additional compilation time, and executable size. I'm not too concerned about that just yet.

Now, what if I wanted to build a system where everything had to inherit from something, but there was no need for virtual members?

That sounds a little odd to me. You'd have to question why you're choosing to use inheritance there.

Would that generate a vtable for each sub-class, or is that compiler-specific?

If there's no virtual then there's no vtable. That's the case for any compiler I'm aware of. But, yes, you are in the hands of the compiler there.

I agree. I think it makes sense that there will be systems, such as the Widget system for menus, to have a base class that everything inherits from. That way, a controller class can iterate through everything, and operate on the objects generically. This type of example heavily suggests the need for virtual methods that could be overridden by sub-classes to do their specific tasks. Now, what if I wanted to build a system where everything had to inherit from something, but there was no need for virtual members? All sub-classes have to inherit from the base class that's being treated as an interface. Would that generate a vtable for each sub-class, or is that compiler-specific?

I should point out that talking about Widgets, or a GUI in general is a special topic. A UI usually follows different design patterns than most other components in say, a game will follow.

Why would you want to inherit without having a vtable?

I'm a recovering abuser of inheritance:lol: I'm starting to realize that templates are a good answer to some cases. I'm under the impression that templates still maintain the performance you'd lose by creating a vtable for sub-classes at the cost of additional compilation time, and executable size. I'm not too concerned about that just yet.

In my opinion becoming an abuser of templates is much worse than an abuser of inheritance, make sure you don't start looking at templates as the magical solution to everything.

Exactly. There is no "one tool fits every solution". Only "one tool can be abused to solve every solution badly" - whether polymorphism, macros (or other pre-processing methods), templates, callbacks (and signals/slots), or any other feature; they all have value in some circumstances, and can cause pain in others.

Games aren't made from a single paradigm. When using ECS, "normal" OOP, procedural programming, or whatever else, don't lock yourself into the mindset that your game's entire architecture needs to fit into one paradigm or pattern. Different parts of your architecture are better suited for different styles of design or different tools.

While the bulk of a game may lean more towards ECS, the rendering sub-system itself may lean in a different direction, data serialization in a different one, big picture networking between the game and the server and the other clients yet another architectural design.
Just because ECS doesn't lend itself to UI very well, I wouldn't call UI a special case.

There are so many different problems, sometimes even specialized languages are designed just to lend themselves better to those problem-types.

Now, what if I wanted to build a system where everything had to inherit from something, but there was no need for virtual members? All sub-classes have to inherit from the base class that's being treated as an interface.

The question becomes, why do all sub-classes have to inherit from a base class? What concrete objective are you aiming for?

Are you wanting to inherit features? Use composition.
Are you wanting to use a common interface at compile-time? Use templates.
re you wanting to use a common interface at runtime? Maybe it'd make sense for certain functionality to be handled by registering callbacks, perhaps using std::function.

And inheritance is the best choice in some situations, so maybe that this is one of those cases.

But you have to give concrete example about what you are wanting to achieve, and why you are wanting to achieve it.

Would that generate a vtable for each sub-class, or is that compiler-specific?

vtables themselves aren't part of the standard. They are just how pretty much every compiler decides to implement the features (virtual functions) that the standard demands be implemented.

This topic is closed to new replies.

Advertisement