Initialize base class with data member from derived class [duplicate] - c++

This question already has answers here:
Order of calling constructors/destructors in inheritance
(6 answers)
Closed 5 years ago.
Consider a code
struct X {
X (int n) {...}
};
struct Base {
Base(X & x) {...}
};
struct Derived : public Base {
Derived() : Base(x), x(2) {}
X x;
};
Code works and i see no issue there but i'm concerned about the look of : Base(x), x(2) statement. First pass the instance to Base and after you initialize the actual object. Is this the the only way to express the intention?

The trick is to derived from one more base class who's function is to own the X.
Note that base class declaration order matters:
struct X {
X (int n) {}
};
struct Base {
Base(X & x) {}
};
struct OwnsAnX {
OwnsAnX(int n) : x_(n) {}
X& get_x() { return x_; }
private:
X x_;
};
struct Derived
: OwnsAnX // note: order is important
, Base
{
Derived()
: OwnsAnX(2)
, Base(get_x())
{}
// x is accessed through the inherited get_x()
};
but it's error prone if you don't keep the correct order of the classes you're inheriting from
This is a valid concern of the OP. The solution is to enable the compiler warning -Wreorder.
Reversing the order of the base classes then yields:
<source>: In constructor 'Derived::Derived()':
<source>:24:23: warning: base 'OwnsAnX' will be initialized after [-Wreorder]
, Base(get_x())
^
<source>:24:23: warning: base 'Base' [-Wreorder]
<source>:22:9: warning: when initialized here [-Wreorder]
Derived()
^~~~~~~

Related

how to initialize base class with members of derived class [duplicate]

This question already has answers here:
warning: derived class's member variable is initialized after base class
(3 answers)
C++: Construction and initialization order guarantees
(5 answers)
Closed 9 months ago.
Beginner here, my simplified code:
A.h
class A{
public:
A(int x);
private:
int _x;
}
A.cpp
A::A(int x)
: _x(x)
{
}
B.h
class B : public A{
public:
B()
private:
int _y = 1;
}
B.cpp
B::B()
: A(1) //works
: A(_y) //doesn't work
{
}
Why does the initialization with a member of B not work, but with a bare integer it does.
I mean I can just go for the working method but I'd like to know the cause.
Thanks for any helpers!:)
Vlad has given you the reason, here's a workaround that avoids the need to duplicate your magic number:
class B : public A{
public:
B();
private:
static const int initial_y = 1;
int _y = initial_y;
};
B::B()
: A(initial_y)
{
}
Demo
A derived class's base classes are fully initialized before any of the derived class's data members are initialized.
In the case of:
class B : public A{
public:
B();
private:
int _y = 1;
}
B::B()
: A(_y)
{
}
Data members that have initial values in their declarations are implicitly handled by the constructor's member initialization list. So, in this case, the compiler treats the above code as-if you had written it like this instead:
class B : public A{
public:
B();
private:
int _y;
}
B::B()
: A(_y), _y(1)
{
}
As you can see, A(_y) is called before _y is initialized, which is undefined behavior.

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.

Constructor definition with virtual multiple inheritance [duplicate]

This question already has an answer here:
Why is Default constructor called in virtual inheritance?
(1 answer)
Closed 6 years ago.
I think an example would describe my problem the best.
struct Base {
Base() = delete;
Base(int x) : x(x) {}
int x;
};
struct Derived1 : virtual Base {
Derived1(int y) : Base(5), y(y) {}
int y;
};
struct Derived2 : virtual Base {
Derived2(int z) : Base(10), z(z) {}
int z;
};
struct Derived3: Derived1, Derived2 {
public:
Derived3(int y, int z) : Derived1(y), Derived2(z) {}
};
And an error I get:
In constructor ‘Derived3::Derived3(int, int)’:
error: use of deleted function ‘Base::Base()’
Derived3(int y, int z) : Derived1(y), Derived2(z) {}
I do not understand why this error occurs. In my opinion all base classes are actually get initialized in this example via their constructors (explicitly Derived1 and Derived2 and implicitly Base through Derived2 (I am not sure here, maybe through Derived1)).
Well, let's do what compiler tells me.
struct Derived3: Derived1, Derived2 {
public:
Derived3(int y, int z) : Base(-1), Derived1(y), Derived2(z) {}
};
It compiles and if I do now this:
Derived3 d = Derived3(7, 9);
std::cout << d.x << std::endl;
std::cout << d.y << std::endl;
std::cout << d.z << std::endl;
I get -1, 7, 9. And it is not what I wanted at all. An idea was to initialize base class with one of its derived classes and I was expecting the first number to be 5 or 10.
So, here is my question:
Why I am forced to explicitly call Base constructor when It is already done in one of the derived classes?
More specifically, as I have multiple inheritance and virtual inheritance, I believe that any instance of Derived3 has exactly one copy of instance of Base class. And I was expecting that this copy of Base is initialized in the most derived class of it (Derived1 or Derived2), but as I clearly can see it does not work in this way =( Where am I wrong?
When you use virtual inheritance, there is only 1 copy of Base. Who should initialize that copy, Derived 1 or Derived 2? There is no way to know. That is why you are forced to do it yourself in Derived 3, so there can be no ambiguity. That is also why you get the output you get instead of 5 or 10.
Without virtual inheritance both Derived 1 and Derived 2 would have their own copies of Base that they would be responsible for, therefore there is no ambiguity. When you force them to inherit from the same base Derived 3 has to take ownership of Base in order to resolve the ambiguities... virtual inheritance is weird at best.

C++ Virtual Inheritance from a non-member function

Coming from a Java/C# background and need a bit of help understanding what is happening here in C++...
class A {
int x;
public:
A(int x) : x(x){}
void f(int y) {
cout << x + y << endl;
}
};
class B : virtual A {
int x;
public:
B(int x) : A(2*x), x(x) {}
virtual void f(int y){
cout << x + 2*y << endl;
}
};
void h(){
B b(5);
A &a = dynamic_cast<A &>(b);
a.f(10);
b.f
}
void g() {
A *a = this;
a->f(10);
B *b = dynamic_cast<B *>(a);
b->f(10);
}
Calling h() is ok but calling g() will not work. Can someone explain why? Also, in the line A(int x) : x(x){} what does : x(x){} do? Same question for B(int x) : A(2*x), x(x) and : A(2*x), x(x).
Thanks so much in advance for your help.
A(int x) : x(x){} what does : x(x){} do?
: x(x) is the initializer list. The variable in the paranthesis is the argument received while the outer one is the member variable. It means member variable x is initialized with the value of the x argument received.
B(int x) : A(2*x)
Here you are calling the base class constructor( i.e, A) that receives an integer. x is the variable received by constructor B. This is a way of calling parameterized base class constructor from derived class constructor. By default, derived class constructor invokes the default base class constructor. In your case, if you don't provide the A(2*x) it fails because the base class has no default constructor.
g() is just a free function and not a member of a class, so this has no meaning. I'm not exactly sure what you're trying to do there
With regards to:
A(int x): x(x)
Your A class has int x as a member. This is calling the constructor of that integer with the x value that is passed into the constructor of A. In my opinion this is bad style and you should differentiate between the two. For example
class A {
int x;
public:
A(int x_in) : x(x_in){}
//...
};
This is equivalent to
class A {
int x;
public:
A(int x_in) {
x = x_in;
}
//...
};
1) As per MSDN (responding to your question related to g());
The this pointer is a pointer accessible only within the nonstatic member functions of a class, struct, or union type. It points to the object for which the member function is called. Static member functions do not have a this pointer.
2) The A(int y) : x(y) {} initializes A::x (the member before () with the value inside the "()" i.e. y (modified variable names for better understanding). Same is the case as with B(int x) : A(2*x), x(x) {}. It calls the base class's (A) constructor with the parameter 2*x and then initializes B::x with the value inside the (), i.e. x.
3) Also, g() wouldn't work because the dynamic_cast<> would throw a compile error since the object that's being casted needs to have at least 1 virtual function. If the only virtual function would be the destructor, then dynamic_cast<> would work.
g is a function at file-scope, aka it doesn't belong to any class. Because of this, you can't use this.
The : x(x)-style expressions are member constructors - they initialize (i.e. call the constructor on) the members of the class.

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.