Can somebody explain me why the address of an object changes when I cast it to an other parent class type in an diamond inherited class structure?
See this example:
#include <iostream>
class A{
public:
A(){};
virtual int a(){
return 0;
};
};
class B: virtual public A{
public:
B(){};
};
class C: virtual public A{
public:
C(){};
};
class D: public B, public C{
public:
D(){};
};
int main(){
A* a = new D();
std::cout << "dynamic_cast<A*>: " << dynamic_cast<A*>(a) << std::endl;
std::cout << "dynamic_cast<B*>: " << dynamic_cast<B*>(a) << std::endl;
std::cout << "dynamic_cast<C*>: " << dynamic_cast<C*>(a) << std::endl;
std::cout << "dynamic_cast<D*>: " << dynamic_cast<D*>(a) << std::endl;
return 0;
}
The output is:
dynamic_cast<A*>: 0x11e3c20
dynamic_cast<B*>: 0x11e3c20
dynamic_cast<C*>: 0x11e3c28
dynamic_cast<D*>: 0x11e3c20
Related
Why does the d instance have different this addresses? Someone told me that in OOP languages, a derived class is simply all the members of the base class, followed by members of its own.
#include <iostream>
#include <memory>
struct A
{
int member;
};
struct B : public virtual A
{
void print_b() { std::cout << static_cast<void*>(this) << " " << static_cast<void*>(&this->member) << std::endl; }
};
struct C : public virtual A
{
void print_c() { std::cout << static_cast<void*>(this) << " " << static_cast<void*>(std::addressof(member)) << std::endl; }
};
struct D : public B, public C
{
void print()
{
print_b();
print_c();
}
};
int main()
{
D d;
d.print();
}
Online outputs:
0x700af9347b90 0x700af9347ba0
0x700af9347b98 0x700af9347ba0
Because the B and C base sub objects are distinct objects in relation to each other and cannot share an address.
Empty base sub objects could be exempted from the requirement of having a unique address, but B and C are not empty.
The following code
class B
{
public:
void f1() {}
};
class C
{
public:
void f2() {}
};
class D : public B, public C
{
public:
virtual void f3() {}
};
int main()
{
cout << sizeof(B) << endl;
cout << sizeof(C) << endl;
cout << sizeof(D) << endl;
system("pause");
return 0;
}
gets a result 1 1 8.So why is 8 not 4(in my computer,a pointer takes 4 bytes)?
B,C do not have vptr, and when D has virtual members, D's Vptr is placed in the Vtable of the first inherited class which is B,since the following code
class B
{
public:
virtual void f1() {} //now is virtual
};
class C
{
public:
void f2() {}
};
class D : public B, public C
{
public:
virtual void f3() {}
};
int main()
{
cout << sizeof(B) << endl;
cout << sizeof(C) << endl;
cout << sizeof(D) << endl;
system("pause");
return 0;
}
gets a result 4,1,4. May somebody explain it to me, thanks a lot!
I have an pure virtual base class and a derived class. I know I am allowed to implement a virtual (not pure) method in the base class.
What I do not understand is why I HAVE to also implement the same method in the derived class if what I want is simply to use the base implementation:
#include <iostream>
using namespace std;
class Abstract {
public:
int x;
Abstract(){
cout << "Abstract constructor" << endl;
x = 1;
}
virtual void foo() = 0;
virtual void bar(){
cout << "Abstract::bar" << endl;
}
};
class Derived : Abstract {
public:
int y;
Derived(int _y):Abstract(){
cout << "Derived constructor" << endl;
}
virtual void foo(){
cout << "Derived::foo" << endl;
}
virtual void bar(){
Abstract::bar();
}
};
int main()
{
cout << "Hello World" << endl;
Derived derived(2);
derived.foo();
derived.bar(); //HERE I HAVE TO DEFINE Derived::bar to use it
return 0;
}
You don’t have to do that. You can do the following:
class Derived : public Abstract {
That way, you can use the public methods from the base class.
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()
Ok, I'm using virtual functions, overloaded functions, and multiple inheritance. Of course this doesn't turn out well.
The scenario: Class base1 has a virtual function that needs to be specified by its child.
Class derived derives from two parents base1 and base2, and should use base2's existing functionality to define base1's virtual function.
This is ok, but awkward of course. The motivation is I cannot change the class base2 and the existing interface already heavily invested in has base1 and base2 class functions of the same name. This is ok, nothing is implemented in base1, it should just redirect to base2.
My problem arises because base2 has several overloaded functions of the same name as the virtual function in question. All of the other overloaded versions become essentially hidden at compile time.
Here's a small demonstration code.
// this version does not compile, overloaded samenameFunc(int, int) cannot be found in the derived class.
#include <iostream>
using namespace std;
class base1 {
public:
virtual void samenameFunc(int scratch) { cout << "from base1: " << scratch << std::endl; }
};
class base2 {
public:
void samenameFunc(int scratch) { cout << "samenameFunc from base2: " << scratch << std::endl; }
void samenameFunc(int scratch, int foo) { cout << "samenameFunc(2 args) from base2: " << scratch << ", " << foo << std::endl; }
};
class derived : public base1, public base2 {
public:
void samenameFunc(int scratch) { base2::samenameFunc(scratch); }// { cout << "from derived: " << scratch << std::endl; }
};
int main()
{
derived d;
d.samenameFunc(66);
d.samenameFunc(77, 88);
return 0;
}
And the compiler errors:
$ g++ inheritance_overload_tester.cc
inheritance_overload_tester.cc: In function ‘int main()’:
inheritance_overload_tester.cc:26: error: no matching function for call to ‘derived::samenameFunc(int, int)’
inheritance_overload_tester.cc:18: note: candidates are: virtual void derived::samenameFunc(int)
If the overloaded samenameFunc(int, int) is renamed, I can compile and function as expected. But remember, I can't actually change base2.
// this version does compile
#include <iostream>
using namespace std;
class base1 {
public:
virtual void samenameFunc(int scratch) { cout << "from base1: " << scratch << std::endl; }
};
class base2 {
public:
void samenameFunc(int scratch) { cout << "samenameFunc from base2: " << scratch << std::endl; }
void anotherFunc(int scratch, int foo) { cout << "anotherFunc(2 args) from base2: " << scratch << ", " << foo << std::endl; }
};
class derived : public base1, public base2 {
public:
void samenameFunc(int scratch) { base2::samenameFunc(scratch); }// { cout << "from derived: " << scratch << std::endl; }
};
int main()
{
derived d;
d.samenameFunc(66);
d.anotherFunc(77, 88);
return 0;
}
If this can't be fixed in the existing presentation, can someone suggest a different object inheritance model to solve my problem?
In the definition of the derived class, you can add a using declaration to make the function from base2 visible:
using base2::samenameFunc;