I'm getting confused why p->a() is calling B::a()?. Is there a paragraph somewhere in the C++ documentation/standard that describes this behavior well?
#include <iostream>
using namespace std;
class A {
public:
A() { cout << "A ctor" << endl; a_instance = this; }
static A *get_instance() { return a_instance; }
static A *a_instance;
void virtual a() { cout << "From base class" << endl; }
};
class B : public A {
public:
B() { cout << "B ctor" << endl; b_instance = this; }
static B *get_instance() { return b_instance; }
static B *b_instance;
void virtual a() { cout << "From derived class" << endl; }
};
A *A::a_instance = 0;
B *B::b_instance = 0;
main()
{
cout << "Create A" << endl;
A ab;
cout << "Create B" << endl;
B abc;
B *ptr = B::get_instance();
A *p = A::get_instance();
cout << "Called from A object type" << endl;
if (p) {
p->a();
}
}
When you create the variable abc, A's constructor sets a_instance to that instance. Despite p being a pointer to an A, since the instance is pointing to a B, it's correctly calling B::a().
To fix this behaviour, you could use the following:
A* A::get_instance()
{
static A a;
return &a;
}
B* B::get_instance()
{
static B b;
return &b;
}
and remove all code that has to do with a_instance and b_instance.
The B constructor calls the A constructor first. That replaces the a_instance that you'd already created.
This chaining of constructors is well defined in the standard. The base is always called first, so that the derived constructor is guaranteed to be working on a valid base object.
What you are experiencing is caused by the design error, which is based on A's constructor initializing the static member using this. Body of this constructor is invoked not only when you are creating the instance of A but also when you are creating the instance of any of its derived classes:
A() { /* ... */ a_instance = this; }
So when you create an instance of type B, before the body of B's constructor is executed, the body of A's constructor is executed at first - this overwrites member a_instance with this within a context of instance of type B, i.e. it makes a_instance to point to this new instance of type B.
What you could do is to place a static variable inside of the getInstance method:
class A
{
public:
static A* getInstance() {
static A s; // <-- instantiated upon first call
return &s;
}
void virtual foo() { std::cout << "From base class" << std::endl; }
protected:
A() { } // <-- protected constructor
~A() { }
A(const A&); // <-- protected copy constructor
A& operator=(const A&); // <-- protected assignment operator
};
then B:
class B : public A
{
public:
static B* getInstance() {
static B s; // <-- instantiated upon first call
return &s;
}
void virtual foo() { std::cout << "From derived class" << std::endl; }
protected:
B() { } // <-- protected constructor
~B() { }
B(const B&); // <-- protected copy constructor
B& operator=(const B&); // <-- protected assignment operator
};
and possible usage:
int main() {
A::getInstance()->foo();
B::getInstance()->foo();
}
that outputs:
From base class
From derived class
B constructor invokes A constructor...
Related
I have the following code:
class A {
public:
A() { cout << "A()" << endl; }
void f() { cout << "A" << endl; }
};
class B : public A {
public:
B() { cout << "B()" << endl; }
void f() { cout << "B" << endl; }
void ff() { cout << "ff()" << endl; }
};
int main()
{
A a = B();
B b;
a = b;
}
How calling A a = B(); will be different from A a = A();? Why is the conversion from derived class to base class possible?
When you do A a = B();, copy constructor of class A should be invoked after default constructor of class B has been invoked (Note: Compiler may remove unnecessary copy using copy elison).
A(const A& other)
{
}
Since, object of class B can be passed to copy constructor of class A, it will be allowed but you may experience object-slicing.
If you are curious to know "how is it possible to pass a derived class object to a method accepting a reference to the base class", read the following:
Is it possible to pass derived classes by reference to a function taking base class as a parameter
I'm struggled over some code where I don't know how to name it and how to solve it. I tried to reduce the code to the following example (so the example itself won't make sense, but it shows the problematic):
struct MyInterface {
virtual ~MyInterface() {
};
virtual void Output() = 0;
};
class A {
public:
MyInterface *myInterface;
A(MyInterface *myInterface) {
std::cout << "this in A constructor: " << this << std::endl;
this->myInterface = myInterface;
}
void CallA() {
this->myInterface->Output();
}
};
class B : public MyInterface, A {
public:
int v;
B(int v) : A(this) {
std::cout << "this in B constructor: " << this << std::endl;
this->v = v;
}
virtual void Output() override {
std::cout << "Whatever" << std::endl;
}
void CallB() {
std::cout << "this in CallB: " << this << std::endl;
this->CallA();
}
};
class Foo {
public:
B b;
Foo() : b(42) {
b = B(41); //This will make an "invalid" B:
//generates B on the Stack but assign the bytes to Foo.b (which is on the the heap)
//so b.myInterface will point to the stack
//after leaving this context b.other will be invalid
}
void Exec() {
b.CallB();
}
};
int main(int argc, char **args) {
Foo *foo = new Foo();
foo->Exec(); //Gives a segfault, because foo->b.myInterface is not valid
return 0;
}
First I thought it has something to do with the inheritance and its virtual methods. But I think the main problematic is the this pointer within the constructors.
So my questions: When b is constructed, the this pointer in the constructors points to the stack. Why doesn't show the this pointer to the target memory (in the heap)? No copy constructor is called - Why?
How can I Name this problem?
The copy constructor isn't called because you aren't creating a new object you are assigning to an existing object. This calls the assignment operator.
This is copy construction:
B b1(42); // construction
B b2(b1); // copy construction
B b3 = b1; // looks like assignment but is actually copy construction
This is assignment:
B b1(42); // construction
b1 = B(43); // b1 already exists we can't copy construct, construct a new object and assign to b1
You need to override the assignment operator:
class B
{
B& operator=(const B& other)
{
// fix references to this here
}
}
Here is some basic C++ outline of code:
#include <cstdlib>
#include <iostream>
#include <thread>
using namespace std;
class M {
public:
M() = default;
~M() {
cout << "Called ~M" << endl;
}
};
class A {
public:
A(int z) : _z(z) {
cout << "Called A(int z)" << endl;
this_thread::sleep_for(chrono::milliseconds(1000));
}
A() {
cout << "Called A()" << endl;
this_thread::sleep_for(chrono::milliseconds(1000));
}
A(const A& a) {
cout << "Called A(const A& a)" << endl;
_z = a._z;
}
A(const A&& a) {
cout << "Called A(const A&& a)" << endl;
_z = a._z;
}
A& operator=(const A& a) {
cout << "Called A& operator=(const A& a)" << endl;
if (&a != this) {
cout << "Executed A& operator=(const A& a)" << endl;
}
}
virtual ~A() {
cout << "Called ~A" << endl;
}
int poll() const { return _z; }
private:
M _m;
int _z = 300;
};
class B : public A {
public:
// _a(10)
B() : _a(std::move(A(10))) {
cout << "Called B()" << endl;
}
virtual ~B() {
cout << "Called ~B" << endl;
}
private:
const A& _a;
};
int main(int argc, char** argv) {
B b;
A* aPtr = &b;
A& aRef = (*aPtr);
cout << aRef.poll() << endl;
return 0;
}
from the setup above I get the following output:
Called A()
Called A(int z)
Called ~A
Called ~M
Called B()
300
Called ~B
Called ~A
Called ~M
My issue is the first line of the output (all the others make sense given the first). I am initializing the member _a in B() : _a(std::move(A(10))), this is forced as _a is const reference member. And the CTOR with int argument gets called as well, however why is the default CTOR called on A? Why no move CTOR? Therefore the temporary object simply seems constructed and destroyed, no real move is happening (as can be seen from the 300 output later on).
Now this issue does not seem related to the move per se but to the behaviour around the const reference member. Because if I change the initialization list to: B(): _a(10) I get the same issue: somehow the default object is assigned to the const reference member and the arguments in the initialization list are ignored. So for B(): _a(10) I get:
Called A()
Called A(int z)
Called B()
300
Called ~B
Called ~A
Called ~M
Basically why is the first line a default constructor? And how do I alter the code so that the 10 from the initialization appears instead of the 300 from the default?
Each object of type B has actually two subobjects of type A. One is the base-class subobject, and the other is the _a member subobject. You call the constructor for the member, but the base-class subobject is default-initialized since you haven't explicitly called its constructor in your initialization list.
You could do it by, for example, the following:
B() : A(arguments) //<--initialize the base-class subobject
, _a(std::move(A(10))) {
cout << "Called B()" << endl;
}
Your B both contains an instance of A and derives from A (which is probably a mistake).
You're passing 10 when you construct a temporary A object, then moving that into the member _a. You're leaving the base class subobject to be default initialized.
To fix that, you need to include the base class in the member initializer list:
B() : A(1010), _a(std::move(A(10))) {
cout << "Called B()" << endl;
}
This initializes the base class subobject of B with 1010 (to distinguish it from the member object).
If I were going to do this, I'd also initialize _a directly, so the ctor would look something like:
B() : A(1010), _a(10) { // ...
A has a static function A::create() that creates an instance of A, does some initialization, and returns a pointer to it.
I want to create a subclass of A and have a similar create() func:
class B : public A {
public:
static B* create();
int val;
//...
}
in this B::create() function I have to do the following:
B* B::create() {
auto b = (B*)A::create();
b -> val = 0;
//...
return b;
}
Is this the right way to do it? What will happen after the cast?
Follow-up: A has a protected/private constructor, How should I write B::create(), or B's constructor? I do want the vars inherited from A to have the same values as those created by A::create() would have
The cast won't do anything sensible unless A::create() returns a pointer to a B object. If A::create() returns a pointer to an object which isn't a B you have undefined behavior.
In C++ you deal with initialization of objects using constructors: the initialization of base classes is inherited and each derived can do whatever custom initialization it needs to do. Your B::create() would just return a suitably constructed object:
B::B()
: A() // initialize base
, val(0) {
// other initialization
}
B* B::create() { return new B(); }
You could make class B a friend of A like this
class A {
public:
static A* createA();
int varA;
private:
friend class B; // Make B a friend so that B can use private constructor of A
A()
{
cout << "In A constructor" << endl;
varA = 5; // Initialize members of A here
}
};
A* A::createA()
{
return new A;
}
class B : public A {
public:
static B* createB();
int varB;
private:
B()
{
cout << "In B constructor" << endl;
varB = -5; // Initialize members of B here
}
};
B* B::createB()
{
return new B;
}
int main()
{
cout << "Create A" << endl;
A* x=A::createA();
cout << "x->varA is " << x->varA << endl;
cout << endl;
cout << "Create B" << endl;
B* y=B::createB();
cout << "y->varA is " << y->varA << endl;
cout << "y->varB is " << y->varB << endl;
cout << endl;
delete x;
delete y;
}
When a new B is made, the constructor of A get called automatically and the members of A will be initialized.
Output is:
Create A
In A constructor
x->varA is 5
Create B
In A constructor
In B constructor
y->varA is 5
y->varB is -5
Another way is to make the constructor of A protected instead of private.
I get the error: No appropriate default constructor for B. However, I don't understand why the compiler wants to call a default constructor, when I give the arguments ii and DONT want to call the default.
#include <iostream>
using namespace std;
class A {
int i;
public:
A(int ii) { i = ii; cout << "Constructor for A\n"; }
~A() { cout << "Destructor for A\n"; }
void f() const{}
};
class B {
int i;
public:
B(int ii) { i = ii; cout << "Constructor for B\n"; }
~B() { cout << "Destructor for B\n"; }
void f() const{}
};
class C:public B {
A a;
public:
C() { cout << "Constructor for C\n"; }
~C() { cout << "Destructor for C\n"; }
void f() const {
a.f();
B::f();
}
};
class D:public B {
C c;
public:
D(int ii) { B(ii); cout << "Constructor for D\n"; }
~D() { cout << "Destructor for D\n"; }
};
int main() {
D d(47);
}
Your parent constructor should be called in the initializer list:
class D:public B {
C c;
public:
D(int ii) : B(ii)/* <- */ { cout << "Constructor for D\n"; }
~D() { cout << "Destructor for D\n"; }
};
Note the /* <- */ comment. That needs to be changed.
What you are doing right now is to create an instance of B() in you class D constructor, which is not being used:
D(int ii) { B(ii); /* <- useless*/ }
D(int ii) { B(ii); cout << "Constructor for D\n"; }
Calls the default constructor of B. The B(ii) creates an temporary object of B which gets destructed as soon as constructor of D returns, In short it does not call the constructor for Base class of object which is being constructed.
Solution:
To be able to call a particular constructor of your Base class you should use Member Initializer list.
D(int ii) : B(ii)
{
}
This code:
class C:public B
{
C() { cout << "Constructor for C\n"; }
};
attempts to call B's default constructor.
You might want:
class C:public B
{
C() : B(0) { cout << "Constructor for C\n"; }
};
but that depends on your logic.
The following is also wrong:
D(int ii) { B(ii); cout << "Constructor for D\n"; }
it should be
D(int ii) : B(ii) { cout << "Constructor for D\n"; }
Calling the base class constructor in the body of the child class constructor merely creates a temporary object which doesn't do anything. To get the behavior you expect, you must call the constructor in the initializer list.
You're creating a D, which is derived from B -- but D's ctor doesn't pass a parameter to B's constructor, which would require that B have a default ctor.
To fix this, you typically need to write D to provide a parameter to B's ctor:
class D : public B {
C C;
public:
D(int ii) : B(ii) { cout << "ctor for D\n"; }
};
You need to realize that base and member subobjects are constructed by the time you enter the body of your constructor! That is, if you have a base or a member which doesn't have a default you need to pass its argument in the member initializer list:
D(int ii): B(ii) { std::cout << "constructor for D\n"; }
The object you constructed in your body of the D constructor is just a temporary object which doesn't really serve any purpose in your case (temporary object may be useful in some cases, though).