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
Related
For instance, I have base class A:
class A {
public:
callA() {
val = 100;
std::cout << this->val << std::endl;
}
int val;
}
class B : public A {
public:
B() {
val = 10;
}
int val;
}
B b;
b.callA();
What will b.callA() print?
And for B inheriting A, if B does not have a field val, will B share an exact reference to A's val, or is it a copy?
Internally, any instance of Class B contains an entire copy of Class A. In fact, when you initialize a new instance of Class B, Class A's constructor is run first. Therefore, when you call a non-virtual function from the base class, it will run as if it were run from the base class, which is internal to the derived class. It can even access the private variables of the base class (which the derived class wouldn't be able to access, it only has access to public/protected variables from the base class).
Example:
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout << "Base constructor!" << endl;
privateVar = 10;
}
void testPrint()
{
cout << "privateVar: " << privateVar << endl;
}
private:
int privateVar;
};
class B : public A
{
public:
B()
{
cout << "Derived Constructor!" << endl;
}
};
int main()
{
B testB;
testB.testPrint();
return 0;
}
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'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...
I have a code snippet below:
#include <iostream>
using namespace std;
class Base {
public:
Base() : b(0) {}
int get();
virtual void sayhello() { cout << "Hello from Base with b: " << b << endl; }
private:
int b;
};
int Base::get() {sayhello(); return b;}
class Derived : public Base {
public:
Derived(double b_):b(b_){}
void sayhello() { cout << "Hello from Derived with b: " << b << endl; }
private:
double b;
};
int main() {
Derived d(10.0);
Base b = d;
cout << "Derived b: " << d.get() << endl;
cout << "Base b: " << b.get() << endl;
}
Run the compiled executable and I find the result is out of my expectation on my llvm-g++ 4.2 machine. The output on my box is as
Hello from Derived with b: 10
Derived b: 0
Hello from Base with b: 0
Base b: 0
What I want to do in the code is to override a member field (b) in Derived class.
Since I think both Base and Derived need to access this field, I define a get member function in Base, thus Derived can inherit it.
Then I try to get the member field from different objects.
The result shows that I still get original b in Base by d.get() instead of that in Derived, which is what I expected the code to do.
Anything wrong with the code (or my understanding)? Is this behavior specified in the specification? What is the right way to override a member field and properly define its getter and setter?
The new b added in the derived class doesn't override base's b. It just hides it.
So, in the derived class you have two b and the virtual method prints corresponding b.
You can't simply override a member field, and as Base::get is compiled, the b variable is resolved to Base::b so this method will always use this value and not a value from another field with the same name in a derived class.
The usual way to override an attribute is to override the way you access it, i.e. override the accessors (getter and setter).
You can achieve something like that by decorating the getter, but the getter return type will always be the same:
class Base {
public:
Base() : b(0) {}
int get();
virtual void sayhello() { cout << "Hello from Base with b: " << b << endl; }
protected:
virtual int getB() {return b;}
private:
int b;
};
int Base::get() {sayhello(); return getB();}
class Derived : public Base {
public:
Derived(double b_):b(b_){}
void sayhello() { cout << "Hello from Derived with b: " << b << endl; }
protected:
int getB() override {return b;} // conversion from double to int
private:
double b;
};
I'm not sure I understand you correctly, but it by "override" you mean "replace", you'd use a template:
#include <iostream>
using namespace std;
template< typename T >
class Base {
public:
Base() : b(0) {}
Base(T b_) : b(b_) {}
T get();
virtual void sayhello() { cout << "Hello from Base with b: " << b << endl; }
protected:
T b;
};
template< typename T >
T Base<T>::get() {sayhello(); return b;}
class Derived : public Base<double> {
public:
Derived(double b_):Base(b_){}
void sayhello() { cout << "Hello from Derived with b: " << this->b << endl; }
};
int main() {
Derived d(10.0);
Base<double>* b = &d;
cout << "Derived b: " << d.get() << endl;
cout << "Base b: " << b->get() << endl;
}
You code in main was also attempting Base b = d; which would lead to slicing, the above fixes that and makes sure you don't accidentially use Base<int> instead of Base<double>.
Live example
you should rewrite your Derived::ctor as follows:
Derived(double _b)
:Base(_b)
{}
And remove filed b in Derived class. Instead mark b in the Base class as protected.
EDIT
Disregard all of this
I've found a problem in your code:
Base b = d;
You're copying derived object to base. It copies only base fields. If you want polymorphism try next:
Base *b = &d;
b->get()
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).