Preferred way to initialize base class members (c++) - c++

I have a base class:
class Base {
protected:
int m_a;
virtual void foo() = 0;
}
And a derived class(es)
class Derived : public Base {
public:
Derived(int a);
}
The base class is abstract, so only derived classes can be created.
How is the better way to implement the derived Ctor?
Derived::Derived(int a) : Base(a) {}
Base::Base(int a) : m_a(a) {}
Or
Derived::Derived(int a) { m_a = a;}
Base::Base(){}
Is it better to remove the member from Base constructor, since it cannot be created alone, OR to keep it on the Base constructor to stay the assignment for him?

Your first solution- giving the base class an explicit constructor - is preferable as general pattern:
it avoids other classes inherited from Base forgetting to initialize m_a. Instead, the signature of the class indicates initialization is required.
if multiple classes inherit from base, and initialization is more complex (e.g. a range check) , this code - and policy - is not distributed over multiple derived classes
if m_a is immutable, constructor initialization is required
derived classes might have more than one CTor, more places to forget
Only downside: a little more typing - as long as you don't count the additional "I'm a little lazy today so don't forget to init m_a in all derived classes constructors"
The "signature announces the requirements" is IMO sufficient to make this the default pattern, so is "the other way requires making m_a protected", as mentioned in the comments.

I would prefer :
Derived::Derived(int a) : Base(a) {}
Base::Base(int a) : m_a(a) {}
By this way you make your code more encapsulated and Base members took care about its init list, there can be some more init logic in base class constructor depending on m_a instead of just initing m_a. In this case you pass initial value to your base constructor and then derived class in his constructor has initialized constructor of base class.
You should try to pass init values to your Base class, imagine you have 5 Derived classes and you need to init base class at all of yours derived ctors.

Related

Virtual Inheritance Base Constructor Mechanics (Diamond Problem) Clarification

The Diamond Problem and Virtual Inheritance are topics that have been discussed endlessly, though while researching them I found myself still uncertain of a few specifics when it comes to calling Base constructors due to the large variety of ways the same terminology was used in different places.
I understood that in the typical Diamond inheritance setup it is the responsibility of the most derived, concrete class to explicitly call the constructor of the base class that is virtually inherited from, lest a default constructor be called (if available); however, I wanted to know exactly what this meant for the constructors of the "middle" classes in the case where the base class does not/cannot have a default constructor.
I did a basic test of this case and would like to confirm that I now correctly understand my findings, just to make sure there are no gotchyas or misconceptions I have.
Note the following code is cutdown to just focus on constructor calls and doesn't demonstrate why I need a diamond inheritance tree in the first place.
class Base
{
private:
std::string mString;
protected:
Base(std::string str) : mString(str) {}
public:
void identify() { std::cout << mString << std::endl; }
};
class DerivedA : public virtual Base
{
public:
DerivedA(std::string str) : Base(str) {}
};
class DerivedB : public virtual Base
{
public:
DerivedB(std::string str) : Base(str) {}
};
class Concrete : public DerivedA, public DerivedB
{
public:
Concrete(std::string str) :
Base(str),
DerivedA("not used"),
DerivedB("not used")
{}
};
int main(int argc, char *argv[])
{
Concrete con("I am concrete");
DerivedA derA("I am DerivedA");
DerivedB derB("I am DerivedB");
con.identify();
derA.identify();
derB.identify();
}
// Output:
// I am concrete
// I am DerivedA
// I am DerivedB
So am I correct in that what happens here is that although I have to call the Base constructor in both Derived classes because there is no default constructor, when Concrete is being constructed the instance of Base is created first via the call to its constructor in Concrete's initialization list, followed by the creation of Derived A and then Derived B; however, in their constructors the call of Base's constructor is ignored, and instead the instance of Base they need that would have resulted from that call is instead provided via a reference to the instance spawned from Concrete's initialization list?
Based on the output, it seems that due to the virtual inheritance the calls to Base's constructor within DerivedA/B's initialization list are only actually used if I instantiate a copy of them directly (which I may actually want to do at times, so this is indeed useful), otherwise the calls to the Base constructor in the most derived class essentially "override" the same constructor calls in the classes higher up the inheritance tree.
Do I understand this correctly?

Derived class constructor taking base class as argument (Is it Good practice?)

I have a two simple classes below, one base and another deriving from it.
In the derived class there are two constructor, one which takes all arguments needed for base and derived, and another which takes a Base class reference itself as argument.
I know the constructor which takes the base class reference as argument is not a good practice.
However, I was wondering why is it not considered a good practice?
It achieves the same thing as the other constructor.
Could someone please clarify why is it not a good OOP practice?
class Base
{
public:
Base(int a, int b):
m_a(a),
m_b(b)
{}
Base(const Base& b):
m_a(b.m_a),
m_b(b.m_b)
{}
~Base() {}
protected:
int m_a;
int m_b;
};
class Derived : public Base
{
public:
// Constructor which takes base class argument and initializes base
Derived(Base &base, int c):
Base(base),
m_c(c)
{}
Derived(int a, int b, int c):
Base(a, b),
m_c(c)
{}
~Derived() {}
private:
int m_c;
};
int main()
{
Base base(1,2);
Derived derived1(base, 3); //
Derived derived2(1,2, 3);
}
It would be necessary to know the context in which you specify the first Derived constructor.
However, maybe it would be more elegant to define it with the const Base parameter. Something like:
Derived(const Base &base, int c):
Base(base),
m_c(c)
{}
Thus, it tells the compiler that protects the state of base object.
Also, if you are using c ++ - 11, then you might be interested in declaring:
using Base::Base;
inside the Derived class, what makes that Derived inherits the constructors of Base. Thus, you could add in your main():
Derived derived3(1,2);
and that would compile perfectly.
In c++-11 you could you also could set a default value for m_c data member. for example
int m_c = 0;
And so the constructor inherited from Base would leave Derived in a consistent state
I believe the code you show is not bad OOP practice. Users of Derived know about, and have access to, Base by virtue of the fact that Derived uses public inheritance. Because of this, you are not adding any dependencies and so are not making anything more restrictive or complex.
That said, even if Derived was using protected or private inheritance, it might not necessarily be bad practice depending on whether users of Derived would otherwise know about class Base.
Imagine this:
class Derived { // no inheritance
public:
void doSomething(const X& b); // `X` could be `Base`, `Foo`, or `std::string` for that matter...
};
Would you call the above bad practice? I think not. The key here, as in the code you presented (assuming you added the const qualifier to the Base& as lrleon suggested,) is that you are using Base as a value type. Derived is not holding a pointer/reference to the base object being passed in, so what you have is normal parameter passing, and there is nothing unusual or bad practice about parameter passing.

How to copy private members of a base class in to a derived class's copy constructor

As title suggests, if I have Derived class's copy constructor I need to copy the Base class's members too however I don't have access to the private members. How do I achieve this?
You have below ways to accomplish this:
(1) Create a base copy constructor (not private) and invoke that in derived copy constructor.
example:
class Base {
private: int i;
public: Base(const Base& copy) : i(copy.i) {}
};
class Derived : public Base {
Derived(const Derived& copy) : Base(copy) {}
};
(2) Make the base members to be copied as protected; But this is less preferable way, since you are making assignment and not initialization.
(3) The least preferable way is to make friend class Derived; inside the body of class Base. Use it only if it's absolutely necessary.

Virtual but not multiple inheritance to call grandparent constructor

I'm having this kind of code:
class Ref {<undefined>};
Ref refObjectForA, refObjectForB;
class Base
{
public:
Base(const Ref & iRef) : _ref(iRef) {}
virtual ~Base() {}
const Ref & ref;
};
class A: public Base
{
public:
A() : Base(refObjectForA) {}
virtual ~A() {}
};
class B: public A
{
public:
B() : Base(refObjectForB) {} // won't compile: Base is not direct base of B
virtual ~B() {}
};
As the attribute is a reference, I think I can only set it in constructor, so I need to call Base constructor in B().
I've found two ways: providing a "forward" constructor in A (but this implies adding code in all classes that might be inherited):
A(const Ref& iRef): Base(iRef)
or using virtual inheritance:
class A: public virtual Base
Second option allows more straightforward code in B implementation but I'm wondering if I'm misusing virtual inheritance in an ugly trick or if it is a valid usecase.
Can I use virtual inheritance in this case?
If no, for what reason?
One of the "unexpected" behaviors I've found is that it's not possible to static_cast a Base pointer to a B pointer because of the virtual inheritance.
Moreover I'm also wondering why it works (I mean why a B().ref == refObjectForB): I would think that the implicit call to default A() constructor in B() would overwrite the ref attribute after explicit Base constructor, but maybe it's not true with virtual inheritance.
The best option I can see if you want to stick to your inheritance hierarchy is to implement protected constructors taking a reference which they'll forward to the Base class. Making a constructor protected makes sure that a (final) instance can't be constructed using this constructor, so it will only be used in subclasses to initialize the super classes.
With some more or less ugly and dangerous macro, this becomes easy to be written:
#define REF_FORWARD_CTOR(ClassName, DirectSuperClassName) \
protected: ClassName(class Ref &r) : DirectSuperClassName(r) {} \
public:
class A : public Base
{
REF_FORWARD_CTOR(A, Base)
public:
A() : Base(refObjectForA) {} // normal ctor
};
class B : public A
{
REF_FORWARD_CTOR(B, A)
public:
B() : A(refObjectForB) {} // normal ctor
};
An alternative design would be to let A and B both derive (directly) from Base. Then, add functionalities by using multiple inheritance and "common classes", maybe private, depending on what they are for:
class Base {
};
class Common {
// common stuff used by both A and B
};
class A : public Base, public Common {
// no further stuff here
};
class B : public Base, public Common {
// add more stuff, or put it in a common super-class again,
// if some classes want to inherit from B again
};
The problem with this design is that functionality in Common can't access the stuff in A and B. To solve this, do one of the following:
If only static stuff is required: Use CRTP to specify A / B in a concrete Common type: Common<A> can then use A::..., but doesn't have anything to do with a concrete instance of A
If an instance is required: provide a pointer / reference in the constructor of Common (slight overhead)
Putting the first two solutions together: Use CRTP, implement wrapper functions in A and B which call functions in Common<A> and Common<B> providing this (which is a A* or B* via an extra parameter.
Same as above, but the class Common can also be non-templated (no CRTP) if you overload / template these functions on this pointer argument ("CRTP on functions", if you want to call it like that). Code speaks louder than words. (Example code is without your references and focuses on the "common class".)
Yes you can technically use virtual inheritance to achieve the goal of providing the reference in the most derived class.
And yes, that's a design smell.
Your classes should not need to be aware of anything but their immediate bases (virtual inheritance is the exception to the rule, when it's needed for other reasons).
Sticking to the proposed classes hierarchy, in order to solve the problem it is enough to use the "using-declaration" to bring the Base's constructor to the protected part of the class A, i.e.:
class A: public Base
{
public:
A() : Base(refObjectForA) {}
virtual ~A() {}
protected:
using Base::Base;
};

How do I call the base class constructor?

Lately, I have done much programming in Java. There, you call the class you inherited from with super(). (You all probably know that.)
Now I have a class in C++, which has a default constructor which takes some arguments. Example:
class BaseClass {
public:
BaseClass(char *name); ....
If I inherit the class, it gives me the warning that there is no appropriate default constructor available. So, is there something like super() in C++, or do I have to define a function where I initialize all variables?
You do this in the initializer-list of the constructor of the subclass.
class Foo : public BaseClass {
public:
Foo() : BaseClass("asdf") {}
};
Base-class constructors that take arguments have to be called there before any members are initialized.
In the header file define a base class:
class BaseClass {
public:
BaseClass(params);
};
Then define a derived class as inheriting the BaseClass:
class DerivedClass : public BaseClass {
public:
DerivedClass(params);
};
In the source file define the BaseClass constructor:
BaseClass::BaseClass(params)
{
//Perform BaseClass initialization
}
By default the derived constructor only calls the default base constructor with no parameters; so in this example, the base class constructor is NOT called automatically when the derived constructor is called, but it can be achieved simply by adding the base class constructor syntax after a colon (:). Define a derived constructor that automatically calls its base constructor:
DerivedClass::DerivedClass(params) : BaseClass(params)
{
//This occurs AFTER BaseClass(params) is called first and can
//perform additional initialization for the derived class
}
The BaseClass constructor is called BEFORE the DerivedClass constructor, and the same/different parameters params may be forwarded to the base class if desired. This can be nested for deeper derived classes. The derived constructor must call EXACTLY ONE base constructor. The destructors are AUTOMATICALLY called in the REVERSE order that the constructors were called.
EDIT: There is an exception to this rule if you are inheriting from any virtual classes, typically to achieve multiple inheritance or diamond inheritance. Then you MUST explicitly call the base constructors of all virtual base classes and pass the parameters explicitly, otherwise it will only call their default constructors without any parameters. See: virtual inheritance - skipping constructors
You have to use initiailzers:
class DerivedClass : public BaseClass
{
public:
DerivedClass()
: BaseClass(<insert arguments here>)
{
}
};
This is also how you construct members of your class that don't have constructors (or that you want to initialize). Any members not mentioned will be default initialized. For example:
class DerivedClass : public BaseClass
{
public:
DerivedClass()
: BaseClass(<insert arguments here>)
, nc(<insert arguments here>)
//di will be default initialized.
{
}
private:
NeedsConstructor nc;
CanBeDefaultInit di;
};
The order the members are specified in is irrelevant (though the constructors must come first), but the order that they will be constructed in is in declaration order. So nc will always be constructed before di.
Regarding the alternative to super; you'd in most cases use use the base class either in the initialization list of the derived class, or using the Base::someData syntax when you are doing work elsewhere and the derived class redefines data members.
struct Base
{
Base(char* name) { }
virtual ~Base();
int d;
};
struct Derived : Base
{
Derived() : Base("someString") { }
int d;
void foo() { d = Base::d; }
};
Use the name of the base class in an initializer-list. The initializer-list appears after the constructor signature before the method body and can be used to initialize base classes and members.
class Base
{
public:
Base(char* name)
{
// ...
}
};
class Derived : Base
{
public:
Derived()
: Base("hello")
{
// ...
}
};
Or, a pattern used by some people is to define 'super' or 'base' yourself. Perhaps some of the people who favour this technique are Java developers who are moving to C++.
class Derived : Base
{
public:
typedef Base super;
Derived()
: super("hello")
{
// ...
}
};
There is no super() in C++. You have to call the Base Constructor explicitly by name.