Delegating work to the superclass' constructor [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C++ superclass constructor calling rules
How do you delegate work to the superclass' constructor? For instance
class Super {
public:
int x, y;
Super() {x = y = 100;}
};
class Sub : public Super {
public:
float z;
Sub() {z = 2.5;}
};
How do I get Sub::Sub() to call Super::Super() so that I don't have to set x and y in both constructors?

Use constructor's member initializer lists:
class Super {
public:
int x, y;
Super() : x(100), y(100) // initialize x and y to 100
{
// that was assignment, not initialization
// x = y = 100;
}
};
class Sub : public Super {
public:
float z;
Sub() : z(2.5) { }
};
You don't need to explicitly call base class' default constructor, it's automatically called before derived class' constructor is ran.
If, on the other hand, you want base class to be constructed with parameters (if such constructor exists), then you need to call it:
class Super {
public:
int x, y;
explicit Super(int i) : x(i), y(i) // initialize x and y to i
{ }
};
class Sub : public Super {
public:
float z;
Sub() : Super(100), z(2.5) { }
};
Furthermore, any constructor that can be called without arguments is a default constructor, too. So you can do this:
class Super {
public:
int x, y;
explicit Super(int i = 100) : x(i), y(i)
{ }
};
class Sub : public Super {
public:
float z;
Sub() : Super(42), z(2.5) { }
};
class AnotherSub : public {
public:
AnotherSub() { }
// this constructor could be even left out completely, the compiler generated
// one will do the right thing
};
And only call it explicitly when you don't want base members to be initialized with default value.
Hope that helps.

Call base constructor in member initialize list if you want to, actually Super() constructor is automatically called.
Don't forgot to make Super destructor virtual.
class Super {
public:
int x, y;
Super() : x(100),y(100) {}
virtual ~Super(){}
};
If deletion through a pointer to a Super should be allowed, then Super destructor must be public and virtual.

Related

Calling base methods from member initializer list

Is it safe to call non-virtual base methods from member initializer list? And virtual?
It is not safe to call any member function (virtual or not virtual) before all base have been initialized. Bellow an example given in the standard ([class.base.init]ยง16):
class A {
public:
A(int);
};
class B : public A {
int j;
public:
int f();
B() : A(f()), // undefined behavior: calls member function but base A not yet initialized
j(f()) { } // well-defined: bases are all initialized
};
class C {
public:
C(int);
};
class D : public B, C {
int i;
public:
D() : C(f()), // undefined behavior: calls member function but base C not yet initialized
i(f()) { } // well-defined: bases are all initialized
};
There are more subtle cases.
As I was saying in the comment:
The first thing that is initialized in the initializer list of a derived class is the base class. Explicitly it looks like this:
class A{ ... };
class B : public A {
int x, y;
B() : A{}, x{...}, y{...} {
...
}
};
Therefore, when initiallizing x and y you can call any non virtual method of A, as it is already constructed.
The second part of the question doesn't have much to do with virtualness - It is simply a question of whether you can call a member function in the constructor. The answer is yes, but - you need to make sure you don't use any uninitialized parts of the object.
e.g.
struct Base {
virtual int f(int i) = 0;
};
struct Derived : public Base {
int x;
int y;
virtual int f(int i) override { return i; }
Derived(int i) : Base{}, x{f(i)}, y{f(x)} {}
};
is fine, but writing ... Derived(int i) : Base{}, x{f(y)}, y{f(i)} ... is not.

Initializing a member in an inherited class with different value of base class

Lets say I have an Entity class with the variable x and it is defined as 0 in that class.
Well then I make a derived class Player but I want the Player's inherited x by default to be 1 and not 0, so that every Player I create has x be 1 by default.
Is this possible?
And if it is, how can I do it?
Yes it's possible, I've read the comments and I gather you want the base member to be private, one option is to inherit base class constructor.
Classes Sample 1
class Entity{
private:
int x;
public:
Entity(int i = 0) : x(i) {} //initialize x to 0
int getX() {return x;}
};
class Player: public Entity{
public:
Player() : Entity(1) {} //inherit base class constructor initializing x to 1
};
This implementation has a potential weakness, it allows for the construction of objects initializing x. If you do not want this you can have a protected constructor that allows derived classes to specify the member value, preventing the construction of objects that can initialize x.
Classes Sample 2
class Entity {
int x = 0;
public:
Entity() = default; //default construtor
int getX(){return x;}
protected:
Entity(int i) : x(i) {} //protected constructor,
};
class Player : public Entity {
public:
Player() : Entity(1) {}
};
Usage
#include <iostream>
using std::cout;
using std::endl;
int main()
{
Entity e;
cout << e.getX() << endl;
Player p;
cout << p.getX();
return 0;
}
Deppending on the compexity of your classes you might also make the protected construtor explicit
Output
0
1
Note that this is a very simplified version, you should observe the rules of class construction like for instance The rule of three/five/zero.
class Entity {
private:
int x;
public:
Entity() : x(0)
{}
void set_x(int y){
x = y;
}
int get_x(){
return x;
}
};
class Player : public Entity {
public:
Player()
{
set_x(1);
}
};

Setting protected member of base class in child class

Since I maked x as protected, shouldn't class B inherit x from A?
class A {
public:
A() {
}
protected:
int x = 0;
};
class B: public A{
B():x(1){
}
};
int main()
{
B b;
}
I'm getting that x does not exist on B
Inherited member variables cannot be set in the initializer list of the constructor. You can either initialize it after your brackets, or do something like this:
class A {
public:
A(int x) : x(x) {
}
protected:
int x = 0;
};
class B : public A {
public:
B() : A(1) {
}
};
int main()
{
B b;
return 0;
}
Since I maked x as protected, shouldn't class B inherit x from A?
Protected doesn't mean that the member is "inherited". A base is inherited, and the base contains all of its members (including the private ones). Protected access specifier means that the derived class has access to the name.
A base can only be initialised with a constructor of base. Members of a base cannot be initialised separately from it. Following would be correct:
struct B {
B(int x) : x(x) {}
protected:
int x = 0;
};
struct D : B{
D() : B(1) {}
};
Since I maked x as protected, shouldn't class B inherit x from A?
Yes, it does. You can use it inside B constructor or any B member functions, eg
B() { x = 2; } // ok
I'm getting that x does not exist on B
However, you can't initialise x in the initialisation list. So thing like this won't work:
B():x{1} // no
You can only initialise x it A constructor where it is a member variable.

Can a private base class member variable be modified in a derived class?

Is there a way to set a private member variable of a base class to a value in the constructor of a derived class?
I understand that's what getter and setter methods are for and what making the variable protected or public is for, but assuming you can't modify the base class, is there any alternate way to set it?
No. It's private. That is the whole point of private.
From the clarifications in the comments - the base class does give you a way to do it via its constructor, so you can use that.
// Assuming MyBaseclass has a 1 int constructor to set the
// private member, then something like this works.
//
MySubclass(int x) : MyBaseclass(x) {}
I understand that's what getter and setter methods are for and what making the variable protected or public is for, but assuming you can't modify the base class, is there any alternate way to set it?
Sure. The alternative way instead of using setter functions in the derived class constructor body, is to use an appropriate constructor from your derived class to call an initializing constructor of the base class (as you state it exists in your comment):
class Base {
public:
Base(int x, int y) : x_(x), y_(y) {}
private:
int x_;
int y_;
};
class Derived : public Base {
public:
Derived() : Base(15,42) {}
// ^^^^^^^^^^^^^
}:
See more details about the member initializer list.
Yes, we can do so by calling a getter function from the base class. Here is an example:
#include<iostream>
using namespace std;
class A{
int x;
public:
void setx(int x1) {
x = x1;
}
int getx() {
return x;
}
};
class B: public A {
};
int main() {
B b;
b.setx(1000);
cout << b.getx();
return 0;
}

Using a different base constructor for a derived class C++

From my understanding the following code will execute in this order:
Derived constructor is called.
Base object is constructed using the default base constructor.
Body of the derived constructor executes.
If so, isn't the member z is assigned a value twice?
class base {
public:
int x, y, z;
base() {x = 0; y = 0; z = 0;};
};
class derived : public base {
public:
derived() {z = 5;};
};
Is there a more efficient way to create an object of class "derived" so it uses a different constructor, in this case, one that would only assign members x and y a value, leaving z to be assigned a value in derived()?
Yes, there is a more efficient way, but it will take more code (thus increasing the maintenance overhead).
class base {
public:
int x, y, z;
// Default constructor
base() {x = 0; y = 0; z = 0;};
// Constructor to be called if you want to override the z value
base(int zValue) { x=0; y=0; z=zValue; };
};
class derived : public base {
public:
derived() : base(5) {};
};
Yes, z is assigned twice in your example, just what it looks like.
To do what you're wanting, you could do something like this, which requires almost exactly the same amount of code (just moving some here and there):
class base {
public:
int x, y, z;
base(int z = 0) : x(), y(), z(z) { }
};
class derived : public base {
public:
derived() : base(5) { } // with this one, z is assigned 5 once
// or
derived() { } // z is assigned 0 once
};
Sure. Use what's called a ctor-initializer:
class base {
public:
int x, y, z;
base(int z = 0) : x(0), y(0), z(z) {};
};
class derived : public base {
public:
derived() : base(5) {}
};
The code after the : and before the first { in the constructor declaration is a ctor-initializer. (Some people call it an "initializer list", but ctor-initializer is what the C++ standard calls it.)
You should always use ctor-initializers whenever you can to initialize class members to some value. While it doesn't really matter for ints, initialization using ctor-initializers can be faster than default constructing class members then assignment.
Definitely, you can do that.
Use member-initialization-list as:
class base {
public:
int x, y, z;
base(int a, int b, int c) : x(a), y(b), z(c) {}
//^^^^^^^^^^^^^^^^^^^ it's member-initialization-list!
};
class derived : public base {
public:
derived() : base(0,0,5) {}
// ^^^^^^^^^^^ call the specific base constructor
};
To elaborate on Andrew's answer, if you wanted to really make sure that all of base's members were set only once, and in the most efficient way possible, you could use a member-list initializer rather than setting values in the constructor.
class base {
public:
int x, y, z;
base() : x(0), y(0), z(0) {};
base( int xval, int yval, int zval ) :
x(xval), y(yval), z(zval)
{ };
};
class derived : public base {
public:
derived() : base( 0, 0, 5 ) {};
};
Most compilers will generate the same code for : x(_x), ... as just setting the values in the constructor, but I've seen a couple that did not.