C++populating base class protected member using derived class constructor - c++

I have something like this:
Class Base
{
public:
Base();
protected:
someType myObject;
}
Class Child:public someNamespace::Base
{
//constructor
Child(someType x):myObject(x){}
}
Class Child, and Base are in 2 different namespaces...
Compiler complains that my Child class does not have a field called myObject
Anyone know why? Is it because its illegal to populate a Base member from a Child constructor?
Thanks

You cannot initialize the inherited member like that. Instead, you can give the base class a constructor to initialize that member, then the derived class can call that constructor.
class Base
{
public:
Base(someType x) : myObject{x} {}
protected:
someType myObject;
}
class Child : public Base
{
public:
//constructor
Child(someType x) : Base(x) {}
}
In general, a class should be responsible for initializing its own members.

The problem here is that you are initializing your inherited myObject in the initialization list. When an object of the derived class is created, before entering the body of the constructor of the derived class the constructor of the base class is called (by default, if base class has default or no parameter constructor, otherwise you have to explicitly call the constructor in the initialization list).
So, when you do :: Class Child:public someNamespace::Base your constructor for the base class has not yet been called, which is why your compiler complains :: Child class does not have a field called myObject, that is you are actually trying to assign a value to something which has not yet been declared and defined! It will get defined after the constructor the Base class enters its execution.
So, your Child class constructor will look something like this ::
Child(someType x) {
myObject = x;
}
Working ideone link :: http://ideone.com/70kcdC
I found this point missing in the answer above, so I thought it might actually help!

Related

Can I do something so that arguments to superconstructor are passed implicitly?

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)

constructor of base class is called while declaring a derived class

I have got two files and a base class in each of them. I want to let some functions in derived class use data members inside base class. The problem that I am facing resembles closely to the one given below:
In file BaseFile.h
class Base{
private:
int a, b;
protected:
//some data members and functions that I want to share with derived class
public:
Base(int apple, int ball):apple(a), ball(b) {}
};
In file DerivedFile.h
#include "BaseFile.h"
class Derived : public Base{ //error in this line
//stuffs
};
Whenever I declare the derived class, I get an error saying 'no matching function for call to Base::Base note:: candidate expects 2 arguments 0 provided'. What could be the cause of this problem?
First, your initializer list in Base class is wrong. Should be a(apple), b(ball).
Second, you do need to initialize Base class in your Derived class, i.e. call its constructor.
Something like
Derived::Derived() :
Base(0,0) {
}
You have a constructor in the base class that requires two parameters but no default constructor. My guess is that your derived class does not declare constructors so the compiler is trying to create a default for you. It then has no way of calling the base constructor as the only one it has required 2 params.
You are getting this error because Base class doesn't have default constructor (which takes 0 arguments) and from derived class constructor base class default constructor is getting called. This can be fixed in two ways:
Add default constructor to base class
Ensure that Base class constructor is always called as Base(int, int).
Also there is a typo in the Base class constructor code
Base(int apple, int ball):apple(a), ball(b) {}
It should be
Base(int apple, int ball):a(apple), b(ball) {}

how to declare default constructor

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.

Why can't Initialize the data member of base class in the constructor initializer list of derived class?

such is the code,and with the error:"illegal member initialization: 'a' is not a base or member",what is the meaning of the error info,and why??
class A{
public:
int a;
};
class B:public A{
public:
B();
};
B::B():a(10){ // put "a(10)" into the constructor body is right
}
By the time the constructor of the derived class is invoked, the base class must already be constructed. So it's already too late. To see why it must be this way, consider:
class Base
{
public:
int i;
Base(int q) : i(q) { ; }
};
class Middle : public Base
{
public:
Middle() : Base(2) { printf("i=%d\n", i); }
};
class Derived : public Middle
{
public:
Derived() : i(3) { ; }
}
Now, think about it. The Middle constructor has to run before the Derived constructor. And the Middle constructor ensures that i is 2. So how can the Derived constructor later re-construct it with a different value?
See this answer for a more complete explanation of what's going on here. Basically, you cannot initialise A::a in the initialiser of B, because it is ill-formed according to the standard.
One more important piece of information - remember that if a class does not initialise a member object via the constructor initialization list, then the default constructor for that member will be invoked before that first statement in the base class constructor is executed. When you use the initialiser, what you are actually doing is specifying a constructor to be used INSTEAD of the default constructor.
Clearly when you are constructing a derived class, the parent class member has thus already been constructed, so you cannot reconstruct the base member again, which is what you are trying to do in this example by including it in the derived class initialisation list.
As an aside, if you all you want is to have the derived class be able to set the value of A::a to a specific value, then use the following code instead:
B::B()
{
a = 10;
}
Because the base class may want to initialize things its own way. The proper method is to call on of the base constructors in the initializer list and let the base ctor initialize itself.

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.