i got a confuse about how does c++ compiler handle "this" pointer in virtual function, my code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <iostream>
using namespace std;
class A {
public:
void print_A(void) {
cout << "A::THIS = " << this << endl;
return;
}
int a;
virtual ~A(void) {
return;
}
};
class B {
public:
virtual void print(void) {
cout << "B::THIS = " << this << endl;
return;
}
int b;
};
class C: public A, public B {
public:
void print(void) {
cout << "C::THIS = " << this << endl;
return;
}
int c;
};
class D {
public:
int d;
virtual ~D(void) {
return;
}
};
class E: public D, public C {
public:
int e;
virtual ~E(void) {
return;
}
};
void global_print(B *pb) {
cout << "pb = " << pb << endl;
pb->print();
return;
}
int main(int argc, char *argv[]) {
E e;
A *pa = &e;
B *pb = &e;
C *pc = &e;
D *pd = &e;
E *pe = &e;
cout << "pa = " << pa << endl;
cout << "pb = " << pb << endl;
cout << "pc = " << pc << endl;
cout << "pd = " << pd << endl;
cout << "pe = " << pe << endl;
pb->print();
pc->print();
pe->print();
global_print(&e);
return 0;
this is result compiled with g++ in my linux:
pa = 0x7ffc1e7c7a80
pb = 0x7ffc1e7c7a90
pc = 0x7ffc1e7c7a80
pd = 0x7ffc1e7c7a70
pe = 0x7ffc1e7c7a70
C::THIS = 0x7ffc1e7c7a80
C::THIS = 0x7ffc1e7c7a80
C::THIS = 0x7ffc1e7c7a80
pb = 0x7ffc1e7c7a90
C::THIS = 0x7ffc1e7c7a80
I can't understand that i send &e to global_print and pb in global_print is equal to 0x7ffc1e7c7a90. And then i invode pb->print(), the this pointer in global_print is 0x7ffc1e7c7a80 which is equel to pc. It seems that the pb->print() convert class B to class C, but class B is the father class of class C, how dose it convert?
And although pb can get addres of C::print by virtual function, it's only a address that havn't enough information to konw that is need to convert class B to class C, so how does the program konw that need to convert class B to class C in the run time?
THANKS a lot! wish have a nice day!
Related
I have a problem with a Diamond inheritance exercise.
I have one base class A. Here is its constructor :
A::A(std::string name) : _hp(10), _ep(10), _ad(0)
{
std::cout << "A object created !" << std::endl;
return ;
}
Then, I have two parent classes B and C. Here are their constructors:
B::B(std::string name) : A(name)
{
std::cout << "B object created !" << std::endl;
this->_hp = 100;
this->_ep = 50;
this->_ad = 20;
return;
}
C::C(std::string name) : A(name)
{
std::cout << "C object created !" << std::endl;
this->_hp = 100;
this->_ep = 100;
this->_ad = 30;
return ;
}
And finally, I have one child class . Here is its constructor:
D::D(std::string name) : A(name + "_comes_from_A")
{
this->_name = name;
std::cout << "D object created !" << std::endl;
this->_hp = C::_hp;
this->_ep = B::_ep;
this->_ad = C::_ad;
return;
}
The D class inherits from class B and C.
The B and C classes both inherits from class A. I did something like this :
class A
{
// code here
protected:
std::string _name;
int _hp;
int _ep;
int _ad;
};
class B : virtual public A
{
// code here
};
class C : virtual public A
{
// code here
};
class D : public B, public C
{
// code here
};
As it can be noticed in the constructor of D class, I want it to inherits _ep from the B class (50) and _hp and _ad from the C class (100 and 30).
However, if I check the value of the _ep value in my D class, (with something like this for instance) :
std::cout << "ENERGY POINTS " << this->_ep << std::endl;
it is always equal to 100 (which comes from the C class).
I have noticed it depends on the order in which I handle inheritance for D class but I would like to be able to access values of any of the parent class from my child class. Can someone help me with that ? Thanks in advance!
MINIMAL REPRODUCIBLE EXAMPLE :
class A
{
public :
A(){
return ;
};
A(std::string name) : _hp(10), _ep(10), _ad(0){
std::cout << "A object created !" << std::endl;
return ;
};
~A(){
std::cout << "A object " << this->_name << " destroyed." << std::endl;
return ;
};
protected:
std::string _name;
int _hp;
int _ep;
int _ad;
};
class B : virtual public A
{
public :
B(){
return ;
};
B(std::string name) : A(name){
std::cout << "B object created !" << std::endl;
this->_hp = 100;
this->_ep = 50;
this->_ad = 20;
return ;
};
~B(){
std::cout << "B object " << this->_name << " destroyed." << std::endl;
return ;
};
};
class C : virtual public A
{
public :
C(){
return ;
};
C(std::string name) : A(name){
std::cout << "C object created !" << std::endl;
this->_hp = 100;
this->_ep = 100;
this->_ad = 30;
return ;
};
~C(){
std::cout << "C object " << this->_name << " destroyed." << std::endl;
return ;
};
};
class D : public B, public C
{
public :
D(){
return ;
};
D(std::string name) : A(name + "_comes_from_a"){
this->_name = name;
std::cout << "D object created !" << std::endl;
this->_hp = C::_hp;
this->_ep = B::_ep;
this->_ad = C::_ad;
std::cout << "HIT POINTS " << this->_hp << std::endl;
std::cout << "ENERGY POINTS " << this->_ep << std::endl;
std::cout << "ATTACK DAMAGE " << this->_ad << std::endl;
return;
}
~D(){
std::cout << "D object " << this->_name << " destroyed." << std::endl;
return ;
};
};
int main(void)
{
D obj_D("TEST");
return (0);
}
Okay, I got my program to work properly. Maybe I didn't explain well what I wanted to do, but I'm posting my solution here.
There are 4 classes A, B, C and D. They all have _hp, _ep and _ad variables.
D inherits from B AND C, which in turn inherit from A.
A
/ \
B C
\ /
D
I wanted my D class to take :
_ep value from the B class
_hp and _ad values from the C class
Here is the minimal reproducible example of the code that worked for me :
# include <iostream>
# include <string>
class A
{
public :
A(){
return ;
};
A(std::string name) : _hp(10), _ep(10), _ad(0){
std::cout << "A object created !" << std::endl;
return ;
};
~A(){
std::cout << "A object " << this->_name << " destroyed." << std::endl;
return ;
};
protected:
std::string _name;
int _hp;
int _ep;
int _ad;
};
class B : virtual public A
{
public :
B(){
return ;
};
B(std::string name) : A(name){
std::cout << "B object created !" << std::endl;
this->_hp = 100;
this->_ep = 50;
this->_ad = 20;
return ;
};
~B(){
std::cout << "B object " << this->_name << " destroyed." << std::endl;
return ;
};
static const int EP = 50;
};
class C : virtual public A
{
public :
C(){
return ;
};
C(std::string name) : A(name){
std::cout << "C object created !" << std::endl;
this->_hp = 100;
this->_ep = 100;
this->_ad = 30;
return ;
};
~C(){
std::cout << "C object " << this->_name << " destroyed." << std::endl;
return ;
};
static const int HP = 100;
static const int AD = 30;
};
class D : public B, public C
{
public :
D(){
return ;
};
D(std::string name) : A(name + "_comes_from_a"){
this->_name = name;
std::cout << "D object created !" << std::endl;
this->_hp = C::HP;
this->_ep = B::EP;
this->_ad = C::AD;
std::cout << "HIT POINTS " << this->_hp << std::endl;
std::cout << "ENERGY POINTS " << this->_ep << std::endl;
std::cout << "ATTACK DAMAGE " << this->_ad << std::endl;
return;
}
~D(){
std::cout << "D object " << this->_name << " destroyed." << std::endl;
return ;
};
};
int main(void)
{
D obj_D("TEST");
return (0);
}
The difference with the example that I posted in the question is that I declared static const int variables (HP, EP and AD) in my B and C classes. Thus, I am now able to access the values either from B or C classes in the constructor of class D. Typically, what I did earlier was wrong :
// before (not working)
this->_hp = C::_hp;
this->_ep = B::_ep;
this->_ad = C::_ad;
// now (working)
this->_hp = C::HP;
this->_ep = B::EP;
this->_ad = C::AD;
The output is now :
A object created !
D object created !
HIT POINTS 100
ENERGY POINTS 50
ATTACK DAMAGE 30
D object TEST destroyed.
C object TEST destroyed.
B object TEST destroyed.
A object TEST destroyed.
In the below code, I expect members of a being inited with gargabe as they are not mentioned in the members-init-list of the called constructor (with two int parameters). Instead, I'm constantly getting 0 in both i and j of a, b and c and I am failing to see why. Could anybody please point me in the right direction?
#include <iostream>
#include <type_traits>
class A {
public:
int i;
int j;
A() = delete;
A(int a, int b) { std::cout << "VOLOLO!" << std::endl; };
};
int
smear_stack(int p)
{
int j = p++;
int a[500] = {};
for(int i = 0; i < 499; i++) {
a[i] = ++j;
}
std::cout << j << std::endl;
return ++j;
}
int main(void)
{
int i = 2;
i = smear_stack(++i);
A a (i, 32 );
std::cout << "a is " << a.i << " " << a.j << std::endl;
A b = { a };
std::cout << "b is " << b.i << " " << b.j << std::endl;
A c = { a.i, a.j };
std::cout << "c is " << c.i << " " << c.j << std::endl;
}
The i and j fields that you are accessing are, indeed, uninitialized. However, you are smearing the wrong part of the stack. It just so happens that on most OSes, the stack is initially all zeros. It even used to be common in C (long ago) to assume that automatic variables in main were zero-initialized.
To see that the memory is indeed uninitialized, it suffices to put something else there. Here's an example:
#include <iostream>
#include <memory>
class A {
public:
int i;
int j;
A() = delete;
A(int a, int b) { std::cout << "VOLOLO!" << std::endl; };
};
union U {
int is[2];
A a;
U() : is{3,4} {}
};
int
main()
{
U u;
std::construct_at(&u.a, 5, 6);
std::cout << u.a.i << ", " << u.a.j << std::endl;
// output:
// VOLOLO!
// 3, 4
}
Hi I have the following piece of code -
class A{
public:
A(){
cout << "In A CTR" << endl;
}
virtual void buildTree() = 0;
void print(){
cout << "int A print This = " << this << endl;
}
};
class B{
public:
B(){
cout << "In B CTR" << endl;
}
virtual A* getBuilder() {
cout << " In B getBuilder , this = " << this << endl;
return NULL;
}
virtual void hell(){
cout << "In B hell This =" << this << endl;
}
void print(){
cout << "in B print This = " << this << endl;
}
B* add(B* child){
cout << "In B add , This = " << this <<endl;
}
};
class C : public A, public B{
public:
C(){
cout << "In C CTR" << endl;
}
A* getBuilder() {
cout << "In C getBuilder , this = " << this << endl;
return this;
}
void print(){
cout << "In C print This = " << this << endl;
}
};
class D : public C{
public:
D(){
cout <<"In D CTR" << endl;
}
void buildTree(){
cout << "buildTree in D , This = " << this << endl;
B *b = NULL;
add(b);
}
void print(){
cout << "In D print This = " << this << endl;
}
};
int main() {
B *root = new D();
root->getBuilder()->buildTree();
return 0;
}
I get the following output :
In C getBuilder , this = 0x7f9aa0500100
buildTree in D , this = 0x7f9aa0500100
In B add , this = 0x7f9aa0500108
I am unable to figure out , why the add() in class B is called . Here is my understanding . Please correct me.
root is a pointer of type B and points to D .
So, when root->getBuilder() is called , it calls the virtual function in class C , which returns a pointer of type A* .
So, now root->getBuilder() returns a pointer of type A pointing to D.
Hence root->getBuilder()->buildTree() is able to call buildTree in D .
But in the buildTree in class D , we are calling add which is defined in class B.
How are we able to call this , as the pointer type is A and should not know nothing about B, functions .
Any help is appreciated.
Thanks
This seems to be the question:
But in the buildTree in class D , we are calling add which is defined
in class B. How are we able to call this , as the pointer type is A
and should not know nothing about B, functions.
Calling buildTree on a pointer type of A* where buildTree is marked as virtual is going to call buildTree on a D* given root is of type D. So add is available to D because D can access the public and protected methods of is superclasses.
The original code example is unnecessarily complicated. The same principle can be examined via the following code:
A *root = new D();
root->buildTree();
What you have is basically this (very simplified):
struct B
{
B* add(B*)
{
std::cout << "B::add\n";
}
};
struct C : B
{
// Nothing relevant
};
struct D : C
{
void buildTree()
{
add(NULL);
}
};
int main()
{
D root;
root.buildTree();
}
The class D is a C. The class C is a B. That means D is a B as well. Therefore D has the member function add.
The pointers and indirection are red herrings in the case of how you can call add from a D member function.
I think I see the problem now, and it's about the interface the classes present to the world.
Again with a basic and simplified example:
struct A
{
void funA();
}
struct B
{
// Nothing relevant
};
struct C : A, B
{
// Nothing relevant
};
Then by doing
B* p = new C;
is valid. But even though the pointer p is pointing to an object of C (which is also an A) it does not have the interface of A (or C for that matter), only of B.
If you want to use the functions in A or C you have to use down-casting to cast it to the correct type:
static_cast<D*>(p)->funA(); // Cast to the type `p` *really* is
This question already has answers here:
Vectors and polymorphism in C++
(4 answers)
Closed 6 years ago.
#include <iostream>
#include <vector>
using std::cout;
using std::cin;
using std::endl;
class base {
int data;
public:
base(int d = 100) : data(d) {}
virtual int getData() const {return data;}
};
class derived : public base {
int dData;
public:
derived(int dd = 32) : base(), dData(dd) {}
virtual ~derived(){}
int getData() const {return dData;}
};
int main(){
std::vector<base> vec;
base A(20);
derived B(32);
vec.push_back(A);
vec.push_back(B);
for(unsigned int i=0; i < vec.size(); i++)
cout << "vector[" << i << "] :" << vec[i].getData() << endl;
base * ptr;
ptr = &A;
cout << "Base pointing: " << ptr->getData() << endl;
ptr = &B;
cout << "Derived pointing: " << ptr->getData() << endl;
}
Above the code,i create a vector which is type of base and put a derived object in it. when i try to read the values i cant get the correct ones. Even though i put 'virtual' statement before the function which has the same name in my classes. But in pointer way there is no problem.
here is the output of code.
vector[0] :20
vector[1] :100
Base pointing: 20
Derived pointing: 32
int main(){
std::vector<base *> vec;
base A(20);
derived B(32);
vec.push_back(&A);
vec.push_back(&B);
for(unsigned int i=0; i < vec.size(); i++)
cout << "vector[" << i << "] :" << vec[i]->getData() << endl;
base * ptr;
ptr = &A;
cout << "Base pointing: " << ptr->getData() << endl;
ptr = &B;
cout << "Derived pointing: " << ptr->getData() << endl;
}
Well, when i use pointer base vector, it gives the correct values. Thank you for your answers.
I am trying to understand how decorator pattern works and how much I can "stretch" it to me needs. Following this example, I have extended classes XYZ. There exist derived classes "KLM" (from XYZ)
Specifically, even though I have a decorator pattern, the derived decorator classes "KLM" have some functionality that does not show up in any of their base classes "XYZ", "D", "I" or "A".
So while normally I would instantiate an object as
I * inKLM = new L( new M( new K( new A )));
This would not allow me to access the K::doVirtR() , L::doVirtS() and M::doVirtT() functions (see code below). To access these I would need to downcast the inKLM pointer using dynamic_cast to each of classes "KLM".
The problem is that I only manage to do this for the leftmost new in the expression above. I have read that polymorphism needs to be maintained in order for the dynamic casting to work, so I have tried to have a virtual destructor in all functions. Still I cannot get the dynamic cast to work for anything other than the "outer" new operation (in this case object of class "L").
Please see this code. How can I make not only "LinKLM" , but also "MinKLM" and "KinKLM" success in dynamic_casting ?
#include <iostream>
#include <list>
using namespace std;
class D; //decorator base
struct I { //interface (for both Base and DecoratorBase
I(){
cout << "\n| I::ctor ";
}
virtual ~I(){
cout << "I::dtor |" ;
}
virtual void do_it() = 0;
virtual void regDecorator(D* decorator) = 0;
virtual void train() = 0;
virtual void et() = 0;
};
class D: public I { //DecoratorBase : has same-named fns as Base (must be exported on I) and calls upon them.
public:
D(I * inner) : m_wrappee(inner) {
cout << "D::ctor ";
regDecorator(this);
}
virtual ~D() {
cout << "D::dtor ";
delete m_wrappee;
}
void do_it() {
m_wrappee->do_it();
}
virtual void et() {
cout << "filling in for lack of et() in derived class\n";
} //almost pure virtual, just not implemented in all derived classes
void train(){
m_wrappee->train();
}
private:
void regDecorator(D* decorator){
m_wrappee->regDecorator(decorator);
}
I * m_wrappee;
};
class A: public I { //Base has all the basic functionality
public:
A() {
cout << "A::ctor " ;
decList.clear();
}
~A() {
cout << "A::dtor |" ;
}
void do_it() {
cout << 'A';
}
void train(){
et();
}
void regDecorator(D* decorator)
{
if (decorator) {
cout << "reg=" << decorator << " ";
decList.push_back(decorator);
}
else
cout << "dec is null!" <<endl;
}
private:
void et()
{
//size_t counter=0;
list<D*>::iterator it;
for( it=decList.begin(); it != decList.end(); it++ )
{
//if ( (*it)->et() )
(*it)->et();
//else
// cout << "couldnt et cnt=" << counter << endl;
//counter++;
}
}
std::list<D*> decList;
};
class X: public D { //DerivedDecoratorX ..
public:
X(I *core): D(core){
cout << "X::ctor ";
}
virtual ~X() {
cout << "X::dtor ";
}
void do_it() {
D::do_it();
cout << 'X';
}
void doX() {
cout << "doX" << endl;
}
protected:
virtual void doVirtR() = 0;
private:
void et(){
cout << "X::et" <<endl;
}
};
class K: public X {
public:
K(I * core):X(core) {
cout << "K::ctor " ;
}
virtual ~K() {
cout << "K::dtor ";
}
void doVirtR(){
cout << "doVirtK" <<endl;
}
};
class Y: public D {
public:
Y(I *core): D(core){
cout << "Y::ctor ";
}
virtual ~Y() {
cout << "Y::dtor ";
}
/*void et(){
cout << "Y::et" <<endl;
}*/
void do_it() {
D::do_it();
cout << 'Y';
}
void doY() {
cout << "doY" << endl;
}
protected:
virtual void doVirtS() = 0;
};
class L: public Y{
public:
L(I * core):Y(core) {
cout << "L::ctor ";
}
virtual ~L() {
cout << "L::dtor ";
}
void doVirtS(){
cout << "doVirtL" <<endl;
}
};
class Z: public D {
public:
Z(I *core): D(core){
cout << "Z::ctor ";
}
virtual ~Z() {
cout << "Z::dtor ";
}
void et(){
cout << "Z::et" <<endl;
}
void do_it() {
D::do_it();
cout << 'Z';
}
void doZ() {
cout << "doZ" << endl;
}
virtual void doVirtT() = 0;
};
class M: public Z{
public:
M(I * core):Z(core) { //must add D(core) here explicitly because of virtual inheritance in M's base class (Z).
cout << "M::ctor " ;
}
virtual ~M() {
cout << "M::dtor ";
}
void doVirtT(){
cout << "doVirtM" <<endl;
}
};
int main(void) //testing dynamic casting
{
I * inKLM = new L( new M( new K( new A )));
L * LinKLM = dynamic_cast<L *>( inKLM);
M * MinKLM = dynamic_cast<M *>( inKLM);
K * KinKLM = dynamic_cast<K *>( inKLM);
cout << endl;
if ( ! MinKLM ) cout << "null MinKLM!" << endl;
if ( ! LinKLM ) cout << "null LinKLM!" << endl;
if ( ! KinKLM ) cout << "null KinKLM!" << endl;
//KinKLM->doVirtR();
//LinKLM->doVirtS();
//MinKLM->doVirtT();
//LinKLM->D::train();
//KinKLM->do_it();
//MinKLM->doZ();
delete inKLM;
cout << endl;
return 0;
}
If you need access to functionality that is unique in some of the inner classes, you may be better off (depending on the particular problem) trying mixin classes. The basic idea is to have a template class inherit its template parameter. I have simplified the classes below but the principle is clear:
#include <iostream>
// your base class
class I {
public:
virtual void do_it() {}
};
// a decorator
template <class Base>
class T1 : public Base {
public:
void do_it() {
std::cout << "T1" << std::endl;
Base::do_it();
}
void unique_in_T1() {
std::cout << "Unique in T1" << std::endl;
}
};
// another decorator
template <class Base>
class T2 : public Base {
public:
void do_it() {
std::cout << "T2" << std::endl;
Base::do_it();
}
void unique_in_T2() {
std::cout << "Unique in T2" << std::endl;
}
};
// yet another decorator
template <class Base>
class T3 : public Base {
public:
void do_it() {
std::cout << "T3" << std::endl;
Base::do_it();
}
void unique_in_T3() {
std::cout << "Unique in T3" << std::endl;
}
};
int main(int argc, const char * argv[]) {
T3<T2<T1<I>>> my_object1;
my_object1.do_it();
my_object1.unique_in_T2();
T1<T3<I>> my_object2;
my_object2.do_it();
my_object2.unique_in_T3();
return 0;
}
Your class D is not needed anymore. The main purpose of that class is to wrap the object that actually does the job while maintaining the interface of I. With mixin classes there is no wrapping anymore as it has been replaced by inheritance, hence there is no need for the D class.
Here is a link to read more.