How can I inherit a constructor from Grandpa(Non-Direct Base) to Son? For example:
class Grandpa
{
public:
Grandpa();
~Grandpa();
};
class Dad : public Grandpa
{
public:
Dad();
~Dad();
};
class Son : public Dad
{
public:
using Grandpa::Grandpa;
~Son();
};
ERROR: "can only inherit constructor from direct base"
There is a way how to make it work?
There is no way to inherit a non-direct base class' constructor. However, you can still use it. If you want to pass a value to Grandpa's constructor from Son's constructor, you can do something like this;
class Grandpa
{
public:
Grandpa(string surname){
// some codes in the constructor
}
~Grandpa();
};
class Dad : public Grandpa
{
public:
Dad(string surname) : Grandpa(surname){};
~Dad();
};
class Son : public Dad
{
public:
Son(string surname) : Dad(surname){};
~Son();
};
Here what we do is simply, passing the value from Son's constructor to Dad's constructor, and it is just propagating to the Grandpa's constructor.
The relation of non virtual inheritance is just as direct and strong as membership: a class constructor absolutely controls the invocation of the constructors of its members and the invocation of the constructors of its direct non virtual bases. When a class is written, the way its members and direct non virtual bases is specified in the source code; changing that could invalidate a fundamental invariant of the class.
Using a non virtual base constructor directly from a further derived class would break the C++ model.
Related
So I get that when you create a diamond in inheritance the most derived class needs to explicitly call the constructor of the virtual class's sub-objects in its initializer list.
But what about classes that inherit from a virtual class without that inheritance creating a diamond itself? e.g. Bow inherits from virtual base class Weapon, does Bow need a call to Object's constructor in its initializer list too and why?
I've become a bit tangled with all the classes inheritances and initializer lists and I just need to clear things up first before continuing and remove any unnecessary calls in my initializer lists.
Object's constructor takes a sf::Vector2f which is two floats. So far I've had Movable, Weapon and Projectile as virtual base classes since they are part of the diamond.
// sf::Vector2f is an SFML data type which consists of two floats
class Object
{
private:
sf::Vector2f m_pos;
public:
Object(sf::Vector2f start_pos) {m_pos = start_pos;};
}
class Movable : virtual public Object
{
public:
Movable(sf::Vector2f start_pos) : Object(start_pos) { ... };
}
class Weapon : virtual public Object
{
public:
Weapon(float shotDelay, bool isStealth) : Object(sf::Vector2f(0,0)) { ... };
}
class Projectile : public Movable
{
public:
Projectile (sf::Vector2f startPos, int damage) : Movable(startPos) { ... };
}
class Bow : public Weapon
{
public:
Bow() : Weapon(BOW_SHOT_DELAY, BOW_STEALTH) { ... };
}
class Grenade : public Weapon, public Projectile
{
public:
Grenade() : Weapon(GRENADE_SHOT_DELAY, GRENADE_STEALTH) {};//for Weapon
Grenade(sf::Vector2f startPos) : Projectile(startPos, GRENADE_DAMAGE);//for Projectile
}
So after some research, the helpful comments, playing around and tidying up my code I figured out the answer and what was going wrong. I was supplying the Object constructor with a default argument so it was being called that way whether I included the call in the initializer list of a class or not.
A class that inherits from a virtual base class must include calls the constructors of the virtual base class's sub-objects in its initializer list if they do not have default constructors.
So in my example, since Bow inherits from virtual base class Weapon which inherits from Object, its initializer list will look like this:
Bow::Bow() : Object(BOW_STARTING_POS), Weapon(BOW_SHOT_DELAY, BOW_STEALTH)
{
//constructor code
}
For completeness I'm adding what the Grenade initializer lists should be when there is no default constructor:
Grenade::Grenade() : Object(GRENADE_STARTING_POS), Weapon(GRENADE_SHOT_DELAY, GRENADE_STEALTH)
{
//weapon constructor code
}
Grenade::Grenade() : Object(GRENADE_STARTING_POS), Projectile(GRENADE_STARTING_POS, GRENADE_DAMAGE)
{
// projectile constructor code
}
P.S. grenade is split into two constructors because my design required it that way. In a different case where you only need one constructor for a class inheriting from two virtual base classes, one initializer list can contain all the constructor calls as such:
Grenade::Grenade() : Object(GRENADE_STARTING_POS), Projectile(GRENADE_STARTING_POS, GRENADE_DAMAGE), Weapon(GRENADE_SHOT_DELAY, GRENADE_STEALTH)
{
//constructor code
}
Is it necessary to always provide your base class with a constructor? For example if I had the following base class, and then some derived classes.
class Animal
{
public:
//Is this constructor necessary?
Animal();
virtual ~Animal();
};
class Zebra: public Animal
{
public:
Zebra();
~Zebra();
};
class Elephant: public Animal
{
public:
Elephant();
~Elephant();
};
Assuming that I am creating Animal pointers and then dynamically allocating new Zebra and Elephant objects. If I never intend to create an Animal object, then is there any actual need to explicitly create an Animal constructor?
You don't need to explicitly provide constructor.
A default one is generated (if you don't provide other constructor).
so
class Animal
{
public:
virtual ~Animal();
};
is sufficient.
Derived classes constructors would call Base class constructor (explicitly of implicitly).
Related: Does "virtual base class in the case of multilevel inheritance" have significance
I have a template class that can be inherited from in order to impart some select functionality. However, it wants to prevent any classes from further inheriting from anything that inherits it.
The following seems to achieve this:
template<typename Child>
class SealingClass
{
public:
/*public methods etc*/
private:
SealingClass() {}
friend Child;
};
//simplify a bit:
#define Seal( x ) public virtual SealingClass< x >
Now, I can inherit from the above class, as follows:
class NewClass: Seal(NewClass) {};
And if I then try inheriting again from NewClass, as in:
class AnotherClass: public NewClass {};
and then make an instance of said class:
AnotherClass a;
I get the desired error, regarding the constructor in SealingClass being private.
So, everything works as I'd like!
However, I have noticed that if I remove the virtual keyword from the define..
#define Seal( x ) public SealingClass< x >
..my instantiation of AnotherClass now works just fine.
I understand that the virtual keyword, in this context, means that only one instance of the base class is defined in cases of multiple inheritance (eg diamond inheritance) where multiple instances of it could exist, leading to ambiguous function calls etc.
But, why does it affect the functionality of the above?
Thanks :)
If use virtual inheritance, the most-derived type has to do the initialization of this virtual base class. If you don't use virtual inheritance, the directly derived type has to do the initialization.
Therefore, the private ctor does not prevent the derived type NewClass from initializing the direct base class SealingClass, and AnotherClass does not have to initialize NewClass if it's not been virtually inherited.
Some examples:
template<typename Child>
class SealingClass {
public: // for now
SealingClass() {}
};
class NewClass : public SealingClass<T> {
public:
NewClass() : SealingClass<T>() {} // allowed, SealingClass<T> is a
// direct base class
};
class AnotherClass : public NewClass {
public:
AnotherClass() : NewClass() {} // allowed, NewClass is a
// direct base class
AnotherClass() : SealingClass<T>() {} // not allowed, SealingClass<T> is
// no direct nor a virtual base class
};
class NewClass_v : public virtual SealingClass<T> {
public:
NewClass_v() : SealingClass<T>() {} // allowed, SealingClass<T> is a
// direct base class
};
class AnotherClass_v : public NewClass_v {
public:
AnotherClass_v() : NewClass_v() {} // allowed, NewClass_virt is a
// direct base class
AnotherClass_v() : SealingClass<T>() {} // allowed, SealingClass<T> is a
// virtual base class
};
Now, if the ctor of SealingClass is private, AnotherClass_virt is not allowed to call this ctor due to the private access specifier and not being a friend.
If you leave out the explicit initialization of a base class (whether virtual or direct), it is default-initialized ([class.base.init]/8), that is, the default ctor is called implicitly (but you still must have access to the ctor, so it's the same as explicitly writting the call to the default ctor).
Some quotes:
[class.base.init]/1
In the definition of a constructor for a class, initializers for direct and virtual base subobjects and non-static data members can be specified by a ctor-initializer
[class.base.init]/7
A mem-initializer where the mem-initializer-id denotes a virtual base class is ignored during execution of a constructor of any class that is not the most derived class.
[class.base.init]/10
In a non-delegating constructor, initialization proceeds in the following order:
First, and only for the constructor of the most derived class, virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.
Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).
Emphasis mine.
I am writing an abstract class that will be a parent for several other classes. I am thinking the copy constructor should be made private because you are using an abstract class and there is nothing to copy. However, I am not a 100% sure.
Am I correct and if I am not why should it be public or protected?
The copy constructor should be private if you do not want objects of the class to be copied. Otherwise, it should be public.
I think protected is the best choice: it leaves the decision on whether or not the object is copyable to the derived classes, while prohibiting the copying at the abstract class level, preventing the dreaded object slicing.
By making the copy constructor private you'll help prevent inadvertent object slicing, where you make a copy of a derived class but lose all the properties of that derived class. The derived classes can make their own copy constructors that are public and do the right thing.
There's one case where the copy constructor should be protected instead of private, when the abstract class has data members. This doesn't happen very often. The base class can copy the base class members while the derived class copies its own members.
class AbstractBase
{
public:
AbstractBase(const std::string &init) : wtf(init) {}
virtual ~AbstractBase() {}
void DoSomething() = 0;
protected:
AbstractBase(const AbstractBase &r) : wtf(r.wtf) {}
const std::string wtf;
};
class Derived : public AbstractBase
{
public:
// ...
Derived(const Derived &r) : AbstractBase(r), moredata(r.moredata) {}
private:
int moredata;
};
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.