473,472 Members | 2,247 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

oo-problem

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
8 1553
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

"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
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
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

"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
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
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
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

11
by: lawrence | last post by:
I asked a lot of questions in May about how to organize OO code. I didn't get great answers here, but someone here suggested that I look the Eclipse library, which was a good tip. Looking at its...
52
by: Tony Marston | last post by:
Several months ago I started a thread with the title "What is/is not considered to be good OO programming" which started a long and interesting discussion. I have condensed the arguments into a...
51
by: Mudge | last post by:
Please, someone, tell me why OO in PHP is better than procedural.
63
by: Davor | last post by:
Is it possible to write purely procedural code in Python, or the OO constructs in both language and supporting libraries have got so embedded that it's impossible to avoid them? Also, is anyone...
1
by: Az Tech | last post by:
Hi people, (Sorry for the somewhat long post). I request some of the people on this group who have good experience using object-orientation in the field, to please give some good ideas for...
8
by: Allan Ebdrup | last post by:
I just had a discussion with one of my fellow programmers. We have a class for doing some logging and sending an email, it has 5 different scenarioes of loggin that are common enough to share a...
17
by: Nick | last post by:
I am doing some research into building web applications using Object Oriented techniques. I have found the excellent patterns section on the MSDN site, but other than that I cannot find any good,...
3
by: Smitro | last post by:
Hi all, I have spent the last couple of days getting my code up to scratch with PHP 5 and MySQL 5. (I still don't quite understand why we had to change to mysqli from mysql) Just a question,...
34
by: Nate | last post by:
Scenario: In a commerce application, there is a Product class. Along with the Product class there is a form (the text that goes in the labels of the input controls) for inputting and updating...
29
by: Brad Pears | last post by:
Here is a simple OO design question... I have a Contract class. The user can either save an existing contract or they start off fresh with a blank contract, fill in the data and then save a...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.