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.
Related
I have a situation where the top class requires a parameter while none of the child classes does. Some class:
class SuperClass {
public:
SuperClass(const int parameter);
}
And it's child:
class NoParametersInConstructorClass : public SuperClass {
public:
// This will cause an error:
// error: no matching function for call to 'SuperClass::SuperClass(const int)'
NoParametersInConstructorClass() : someText("Hello") {};
private:
std::string someText
}
Now the problem I am facing is that I do have an initializer list, but I find it tedious to rewrite the arguments in all child classes. I am lazy I know. I would like this to work without explicitly defining it:
// Works even though NoParametersInConstructorClass(const int) isn't defined
NoParametersInConstructorClass variable(66);
Of course, if there is no way, there is no way, but is there?
All the derived classes have to pass some value to the base class. It will be easy for the derived classes to have a default constructor in the base class that is in the protected section. You can initialize the member data of the base class that makes sense for the derived classes.
class SuperClass {
public:
SuperClass(const int parameter);
protected:
SuperClass() : SuperClass(10) {} // Delegate to the other constructor.
}
If your problem is that you have a certain set of children, all of which need the SuperClass constructor to be called with the same default argument, all you need to do is to introduce an intermediary with no-argument constructor, which would call the SuperClass::SuperClass with the magic number.
Make the parameter defaulted.
class SuperClass {
public:
SuperClass(const int parameter = DEFAULT);
}
You can then chose to include the constructor in your initialize list, or use the default.
Default value:
class NoParameterChildDefault : public SuperClass
{
public:
NoParameterChildDefault() : someText("Hello") { ... } // uses value DEFAULT.
};
Explicit Value:
class NoParameterChildExplicit : public SuperClass
{
public:
NoParameterChildExplicit() : SuperClass(5), someText("Hello") { ... } // uses value '5'.
};
You may wanna change your default child constructor:
class NoParametersInConstructorClass : public SuperClass {
public:
NoParametersInConstructorClass(int n =0) : SuperClass(n)someText("Hello") {};
private:
std::string someText
}
This way both NoParametersInConstructorClass variable(66); and NoParametersInConstructorClass variable; will work.
To answer your edited question:
You can use the using keyword to make the derived class use the base class constructor:
class NoParametersInConstructorClass : public SuperClass {
public:
using SuperClass::SuperClass;
NoParametersInConstructorClass() : someText("Hello") {};
private:
std::string someText
}
You have to somehow define a constructor for the derived class. You can't just call the base class constructor for the derived class without the using statement.
Let's suppose you can't (or you won't) modify the base class to add a default constructor, you have to call the constructor of the base class in its valid form (with argument) in initialization list of every derived class (like here)
I have a Base class that I can't modify the source code. I make a derived class from it and I am trying to make a no-argument constructor for this derived class. The problem is that I can't define the constructor for two reasons:
There is not a non-argument constructor defined for the base class to use it.
I can't pass a default value for the constructor of the base.
class base
{
public:
base (A arg)
{
}
};
class derived : public base
{
public:
derived () : base (arg) //ERROR
{
}
};
Is there a solution to define a non-argument constructor for the derived class?
Cordialement,
Since you cannot change the base class the only option left is to pass an argument to its constructor. You can do this quite easily by constructing a temporary instance of A and passing it to the base class in your ctor initialized list of derived classes.
derived::derived () : base (A())
{
}
In the code above base(A()) will create a temporary instance of A and pass it to the constructor of base.
I have an abstract base class that needs some objects passed to its constructor to initialize its members. But I would like to get rid of passing those objects through the derived class constructor.
class Derived : public Base
{
public:
Derived(type one, type two, type three) : Base(one, two, three)
{
// ...
The objects passed to the base classes are the same instances for all created derived classes. Is there a way to bind them to the base class' constructor, so that I don't have to forward them through the derived class' constructor?
// do some magic
// ...
class Derived : public Base
{
// no need for an explicit constructor anymore
// ...
In C++11 you can inherit constructors to the base class. It seems this would roughly do what you need:
class derived
: public base {
public:
using base::base;
// ...
};
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.
Is there a way to force a derived class to use the constructor of the abstract base class? It must not be a real constructor, I have an open mind about creative solutions.
class Abstract
{
private:
int Member;
string Text;
public:
Abstract(int Member, string Text)
{
this->Member = Member;
this->Text = Text;
}
// e.g. defining virtual functions
}
For example my abstract class has some private members which every derived class should also have. And they should be defined in the constructor, even against the will of the derived class.
I am aware that constructors are not inherited. But is there a workaround to produce a similar behavior?
As suggested by other users, you must call the base class constructor into the initializer list of derived class constructor.
But there's another cool solution bringed up by C++11: the inherited constructors:
class Base
{
Base(int Member, string Text) { };
};
class Derived : public Base
{
using Base::Base; // <-- Brings to derived the Base's constructor.
};
But you must assure that your compiler can use C++11 features; and of course, study if the inherited constructor conforms to your requirements instead of using it just because it's cool.
Use initializer list of the derived class' constructor.
class Base
{
Base(int Member, string Text) { //...
}
};
class Derived : public Base
{
Derived(int Member, string Text) : Base(Member, Text) {
// ^^^^^^^^^^^^^^^^^^
// ...
}
};