Virtual Inheritance : Base Ctor not calling in Most Derived Class? - c++

class Base
{
public:
Base(){}
Base(int k):a(k)
{
}
int a;
};
class X:virtual public Base
{
public:
X():Base(10){}
int x;
};
class Y:virtual public Base
{
public:
Y():Base(10){}
int y;
};
class Z:public X,public Y
{
public:
Z():X(10){}
};
int main()
{
Z a;
cout << a.a;
return 1;
}
In the above case, for Z():X(10){} Base(int k):a(k) is not calling, but when i change to Z():Base(10){} the Base(int k):a(k) is called. Why ?
Thank you.

Because you used the virtual keyword - that's exactly what it does.
You have to explicitly initialize Base in the initializer list of Z in order to disambiguate between the initialization in X and the initalization in Y.

See this question. The gist is, that when using virtual inheritance you have to call the base class constructor explicitly.

The initializer list in the most derived constructor is used to initialize your base classes. Since class Z inherits from class X and Y which inherits from a common base class, the virtual keyword is used to create only a single subobject for the base class in order to disambiguate when accessing the data member a.

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.

Assign static variable to non-static variable

Consider the Base class where A class and BaseB class are derived. From BaseB is derived C class. All clases inherit non-static variable “y” but in the case of BaseB and C class “y” have the same value.
I resolved this situation with the following code:
class Base {
protected:
int y;
virtual void registerValue()
{
y = 5;
}
};
class A : public Base {
};
class BaseB : public Base {
protected:
static int x;
virtual void registerValue()
{
// Process x ...
y = x;
}
};
class C : public BaseB {
};
int BaseB::x = 3;
int main() {}
It works but is it right to assign static variable to non-static variable for this case?
It's fine to do from a language legality perspective, but it's a little odd.
Presumably you can't make Base::y static since that would interfere with the behaviour of class A?
You just need to be aware of the fact that instances of BaseB will all share the same x, but could have different values of y. Is that the intended behaviour?
Personally I'd consider making void registerValue() a pure virtual function in the base class, and expect all derived classes to implement that method including all necessary storage for its implementation. Perhaps that necessitates a base class function virtual int getRegistedValue() = 0 too?

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;
}

Base class functions that use derived class variables

In c++, Is there a standard way to create a function in a base class that can use the variables of derived classes?
class Foo{
private:
int x;
public:
Foo(){
x = 2;
}
void print(){
std::cout << x << std::endl;
}
};
class Derived : public Foo{
private:
int x;
public:
Derived(){
x = 4;
}
};
void main()
{
Derived a;
a.print();
}
This code prints the variable of the base class ( 2 ). Is there a way to make a function used by many derived classes to use the class's private variables without passing them as parameters?
Edit: My intentions are, to avoid writing the same code for each derived class.
For example, I want a get_var() in all, but this function should return the variable of that own class. I know I can make virtual and override, but I was looking for a way that I don't need to write again and again.
No, it is not possible for the base class to access anything in the derived class directly. The only way for a derived class to share anything with its base class is by overriding virtual member functions of the base class.
In your case, however, this is not necessary: the derived class can set variable x in the base class once you make it protected, and drop its own declaration as unnecessary:
class Foo{
protected: // Make x visible to derived classes
int x;
public:
Foo(){
x = 2;
}
void print(){
std::cout << x << std::endl;
}
};
class Derived : public Foo{
public:
Derived(){
x = 4;
}
};

Does C++ require you to initialize base class members from its derived class?

class Base {
public:
int a;
Base():a(0) {}
virtual ~Base();
}
class Derived : public Base {
public:
int b;
Derived():b(0) {
Base* pBase = static_cast<Base*>(this);
pBase->Base();
}
~Derived();
}
Is the call to the base class constructor necessary or does c++ do this automatically? e.g.
Does C++ require you to initialize base class members from any derived class?
The base class's constructor will automatically be called before the derived class's constructor is called.
You can explicitly specify which base constructor to call (if it has multiple) using initialization lists:
class Base {
public:
int a;
Base():a(0) {}
Base(int a):a(a) {}
};
class Derived {
public:
int b;
Derived():Base(),b(0) {}
Derived(int a):Base(a),b(0) {}
};
Base class constructors are called automatically (and before derived class contructors). So you need not, and must not, try to call base constructors manually.