By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,301 Members | 1,394 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,301 IT Pros & Developers. It's quick & easy.

oo-problem

P: n/a
Hi!
Can anyone tell me why the output of this program is in both cases "from
A!" an not "from B!" or "from C!" ?

Thanks a lot for helping me,
Jan.

//CODE///////////////////////////////////////////////////////

#include <iostream>
using namespace std;

class AImpl;
class A
{
public:
A();
virtual ~A();
const char * GetAddress();
private:
AImpl *pImpl;
};

class BImpl;
class B : public A
{
public:
B();
virtual ~B();
private:
BImpl *pImpl;
};

class CImpl;
class C : public A
{
public:
C();
virtual ~C();
private:
CImpl *pImpl;
};

class AImpl
{
public:
char a[2000];
AImpl()
{
strcpy(a, "from A!");
};
~AImpl(){};
const char * GetAddress()
{
return a;
}
};

class BImpl : public AImpl
{
public:
BImpl()
{
strcpy(a, "from B!");
};
~BImpl(){};
};

class CImpl : public AImpl
{
public:
CImpl()
{
strcpy(a, "from C!");
};
~CImpl(){};
};

A::A()
{
pImpl = new AImpl();
}

const char * A::GetAddress()
{
return pImpl->GetAddress();
}

B::B()
{
pImpl = new BImpl();
}

C::C()
{
pImpl = new CImpl();
}

A::~A()
{
delete pImpl;
}

B::~B()
{
delete pImpl;
}

C::~C()
{
delete pImpl;
}

int main(int argc, char* argv[])
{
B m_xyz;
cout << m_xyz.GetAddress() << endl;
C m_uvw;
cout << m_xyz.GetAddress() << endl;
return 0;
}

Jul 22 '05 #1
Share this Question
Share on Google+
8 Replies


P: n/a
Jan Boehme wrote:
Hi!
Can anyone tell me why the output of this program is in both cases "from
A!" an not "from B!" or "from C!" ?

Thanks a lot for helping me,
Jan.

//CODE///////////////////////////////////////////////////////

#include <iostream>
using namespace std;

class AImpl;
class A
{
public:
A();
virtual ~A();
const char * GetAddress();
private:
AImpl *pImpl;
};

class BImpl;
class B : public A
{
public:
B();
virtual ~B();
private:
BImpl *pImpl;
};

class CImpl;
class C : public A
{
public:
C();
virtual ~C();
private:
CImpl *pImpl;
};

class AImpl
{
public:
char a[2000];
AImpl()
{
strcpy(a, "from A!");
};
~AImpl(){};
const char * GetAddress()
{
return a;
}
};

class BImpl : public AImpl
{
public:
BImpl()
{
strcpy(a, "from B!");
};
~BImpl(){};
};

class CImpl : public AImpl
{
public:
CImpl()
{
strcpy(a, "from C!");
};
~CImpl(){};
};

A::A()
{
pImpl = new AImpl();
}

const char * A::GetAddress()
{
return pImpl->GetAddress();
}

B::B()
{
pImpl = new BImpl();
}

C::C()
{
pImpl = new CImpl();
}

A::~A()
{
delete pImpl;
}

B::~B()
{
delete pImpl;
}

C::~C()
{
delete pImpl;
}

int main(int argc, char* argv[])
{
B m_xyz;
cout << m_xyz.GetAddress() << endl;
C m_uvw;
cout << m_xyz.GetAddress() << endl;
return 0;
}


You redefined pImpl in B and C. Since you dont overwrite your virtual method
GetAddress() in B and C, only the implementation of A will be used. This
will result in
const char * A::GetAddress()
{
return A::pImpl->GetAddress();
}
^-- !!!

For the behavior you desire, you need to overwrite getAddress() in B and C.
BTW, it's quite bad to create data members of the same name in base and
derived classes. Avoiding this will also avoid your problem.

--
Dipl.-Inform. Hendrik Belitz
Central Laboratory of Electronics
Research Center Juelich
Jul 22 '05 #2

P: n/a

"Jan Boehme" <ai*****@hotmail.com> wrote in message
news:br*************@ID-77850.news.uni-berlin.de...
Hi!
Can anyone tell me why the output of this program is in both cases "from
A!" an not "from B!" or "from C!" ?

Thanks a lot for helping me,
Jan.

[SNIP]

You have to keep in mind that inheriting class B from class A results in B
having a part of A incorporated, which is what you normally want. Now you
supply the GetAddress() function in class A only which operates on the
implementation pointee of A! Thus calling this function from the derived
class B (without overriding it!) it's perfectly okay that the operation is
performed on the implementation pointee of A as this part is included in
class B. What you have to do is to supply the same function also in class B
operating on the pImpl pointer of B to get the behavior you expect. BTW it's
not a very good practice to have variables of the same name in base &
derived classes. This normally leads to confusion which you have already
experienced. Some other remarks: the dtor of AImpl should be virtual as you
derive from this class and don't forget to handle copy ctor & assignment in
your A, B, C classes or the next problem will be waiting around the corner.

HTH
Chris

Jul 22 '05 #3

P: n/a
Hendrik Belitz schrieb:
You redefined pImpl in B and C. Since you dont overwrite your virtual method
GetAddress() in B and C, only the implementation of A will be used. This
will result in
const char * A::GetAddress()
{
return A::pImpl->GetAddress();
}
^-- !!!

For the behavior you desire, you need to overwrite getAddress() in B and C.
BTW, it's quite bad to create data members of the same name in base and
derived classes. Avoiding this will also avoid your problem.


I partly understand your explanation und I know how to solve the problem.
Alternatively I added a function to set the address-value a in the base
class.
Why this don't work?

Thanks, Jan.

#include <iostream>
using namespace std;

class AImpl;
class A
{
public:
A();
virtual ~A();
const char * GetAddress();
void SetAddress(const char * par);
private:
AImpl *pImpl;
};

class BImpl;
class B : public A
{
public:
B();
virtual ~B();
private:
BImpl *pImpl;
};

class CImpl;
class C : public A
{
public:
C();
virtual ~C();
private:
CImpl *pImpl;
};

class AImpl
{
public:
char a[2000];
AImpl()
{
SetAddress("from A!");
};
~AImpl(){};
const char * GetAddress()
{
return a;
}
void SetAddress(const char * par)
{
strcpy(a, par);
}
};

class BImpl : public AImpl
{
public:
BImpl()
{
SetAddress("from B!");
};
~BImpl(){};
};

class CImpl : public AImpl
{
public:
CImpl()
{
SetAddress("from C!");
};
~CImpl(){};
};

A::A()
{
pImpl = new AImpl();
}

const char * A::GetAddress()
{
return pImpl->GetAddress();
}

void A::SetAddress(const char * par)
{
pImpl->SetAddress(par);
}

B::B()
{
pImpl = new BImpl();
}

C::C()
{
pImpl = new CImpl();
}

A::~A()
{
delete pImpl;
}

B::~B()
{
delete pImpl;
}

C::~C()
{
delete pImpl;
}

int main(int argc, char* argv[])
{
B m_xyz;
cout << m_xyz.GetAddress() << endl;
C m_uvw;
cout << m_xyz.GetAddress() << endl;
return 0;
}
Jul 22 '05 #4

P: n/a
Hi!

Chris Theis schrieb:
You have to keep in mind that inheriting class B from class A results in B
having a part of A incorporated, which is what you normally want. Now you
supply the GetAddress() function in class A only which operates on the
implementation pointee of A! Thus calling this function from the derived
class B (without overriding it!) it's perfectly okay that the operation is
performed on the implementation pointee of A as this part is included in
class B. What you have to do is to supply the same function also in class B
operating on the pImpl pointer of B to get the behavior you expect. BTW it's
not a very good practice to have variables of the same name in base &
derived classes. This normally leads to confusion which you have already
experienced. Some other remarks: the dtor of AImpl should be virtual as you
derive from this class and don't forget to handle copy ctor & assignment in
your A, B, C classes or the next problem will be waiting around the corner.


Thanks for your explanation. This is only a small snippet to focus to
the main problem. I already thought the copy ctors & assignments are the
problem and tried it out.
But why it don't work by adding also a set-method to the base class and
call in the c'tors of the derived classes. It should perform the
operation at the implementation pointee of A?
Thanks, Jan.

Jul 22 '05 #5

P: n/a

"Jan Boehme" <ai*****@hotmail.com> wrote in message
news:br***********@ID-77850.news.uni-berlin.de...
Hi!
[SNIP] Thanks for your explanation. This is only a small snippet to focus to
the main problem. I already thought the copy ctors & assignments are the
problem and tried it out.
But why it don't work by adding also a set-method to the base class and
call in the c'tors of the derived classes. It should perform the
operation at the implementation pointee of A?
Thanks, Jan.


Try the following in your code just for a test. Declare the pImpl member in
class B public and add the following line to main:

cout << m_xyz.pImpl->a << endl;
cout << m_xyz.GetAddress() << endl;

What you'll get is that the line will deliver "from B" whereas the second
statement will get you "from A". Thus you can see that the value for pImpl
inside B has been set correctly, but calling GetAddress() obviously operates
on the part of class A which is contained inside B, as already explained.

HTH
Chris
Jul 22 '05 #6

P: n/a
Jan Boehme wrote:
Hendrik Belitz schrieb:
You redefined pImpl in B and C. Since you dont overwrite your
virtual method GetAddress() in B and C, only the implementation of
A will be used. This will result in
const char * A::GetAddress()
{
return A::pImpl->GetAddress();
}
^-- !!!

For the behavior you desire, you need to overwrite getAddress() in
B and C. BTW, it's quite bad to create data members of the same
name in base and derived classes. Avoiding this will also avoid
your problem.
I partly understand your explanation und I know how to solve the
problem. Alternatively I added a function to set the address-value a
in the base class.
Why this don't work?


[snip]

int main(int argc, char* argv[])
{
B m_xyz;
cout << m_xyz.GetAddress() << endl;
C m_uvw;
Because you are printing m_xyz two times :-)
cout << m_xyz.GetAddress() << endl; // <====
//you probably meant:
cout << m_uvw.GetAddress() << endl;
return 0;
}


--
To mail me directly, remove the NO*SPAM parts in
NO***********@gmx.netNO*SPAM
Jul 22 '05 #7

P: n/a
Jan Boehme wrote:
Hi!
Can anyone tell me why the output of this program is in both cases
"from A!" an not "from B!" or "from C!" ?

Thanks a lot for helping me,
Jan.


[snip]

Hi,

besides the solved problems with your first implementation, why are you
redefining a pimpl pointer in each derived class? This means that A will
carry around a AImpl, B an AImpl from A and a BImpl, and so on.

As you derive your Implementation hiearchy paralell to the "interface"
hiearchy, you can do it this way:

#include <iostream>
class AImpl;
class A
{
public:
A();
virtual ~A();
const char * GetAddress();
protected://A does the imp handling for you
void SetImp(AImpl* imp);
private:
AImpl *pImpl;
};

class BImpl;
class B : public A
{
public:
B();
virtual ~B();
};

class CImpl;
class C : public A
{
public:
C();
virtual ~C();
};

class AImpl
{
public:
AImpl()
{
SetA("from A!");
};
virtual ~AImpl(){};//virtual dtor!!
const char * GetAddress()
{
return a;
}
void SetA(const char* aa)
{
a = aa;
}
private:
const char* a;
};

class BImpl : public AImpl
{
public:
BImpl()
{
SetA("from B!");
};
virtual ~BImpl(){};
};

class CImpl : public AImpl
{
public:
CImpl()
{
SetA("from C!");
};
virtual ~CImpl(){};
};

A::A()
{// A uses AImpl
SetImp(new AImpl());
}
void A::SetImp(AImpl* imp)
{
pImpl = imp;
}
const char * A::GetAddress()
{
return pImpl->GetAddress();
}

B::B()
{//B uses BImpl, which is derived from AImpl
SetImp(new BImpl());
}

C::C()
{//C uses CImpl, which is indirectly derived from AImpl
SetImp(new CImpl());
}

A::~A()
{
delete pImpl;
}

B::~B()
{
}

C::~C()
{
}

int main(int argc, char* argv[])
{
B m_xyz;
std::cout << m_xyz.GetAddress() << std::endl;
C m_uvw;
//You really meant this or is it a typo?
//cout << m_xyz.GetAddress() << endl;
std::cout << m_uvw.GetAddress() << std::endl;
return 0;
}

HTH,
Andy
--
To mail me directly, remove the NO*SPAM parts in
NO***********@gmx.netNO*SPAM
Jul 22 '05 #8

P: n/a
Hi Andreas!

Andreas Mueller schrieb:
As you derive your Implementation hiearchy paralell to the "interface"
hiearchy, you can do it this way: [snip] A::A()
{// A uses AImpl
SetImp(new AImpl());
}
void A::SetImp(AImpl* imp)
{
pImpl = imp;
}
const char * A::GetAddress()
{
return pImpl->GetAddress();
}

B::B()
{//B uses BImpl, which is derived from AImpl
SetImp(new BImpl());
}

C::C()
{//C uses CImpl, which is indirectly derived from AImpl
SetImp(new CImpl());
}


Your solution looks just like the way I was looking for. I started to
break up this parallel inheritance and began to put all the stuff in one
Impl class and create only an outer class hierachie.
Thanks for helping me out here.
Jan.

PS: Yes, I meant m_xyz.GetAddress() AND m_uvw.GetAddress(). That was a typo.

Jul 22 '05 #9

This discussion thread is closed

Replies have been disabled for this discussion.