Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Composition using references

Reply
Thread Tools

Composition using references

 
 
anongroupaccount@googlemail.com
Guest
Posts: n/a
 
      12-10-2005
I have an ABC with a protected member that is a reference to an object
of an ABC type:

class ABC
{
public:
virtual ~ABC() = 0;
protected:
AnotherABC& _member;
}

The idea is that my concrete classes will derive from ABC and set
_member in their initialization lists to the specific type of
AnotherABC that the particular class needs. However, this can't be done
as the constructors of the derived classes complain about there being
no default constructor for ABC.

Should I simply replace the reference with a const pointer, or should I
rethink this and save myself from a potentially nasty design flaw? Is
there a design pattern I could use here?

 
Reply With Quote
 
 
 
 
Thomas Tutone
Guest
Posts: n/a
 
      12-10-2005
wrote:
> I have an ABC with a protected member that is a reference to an object
> of an ABC type:
>
> class ABC
> {
> public:
> virtual ~ABC() = 0;


your destructor should be protected, not public.

> protected:



your data member should be private, not protected.

> AnotherABC& _member;
> }



> The idea is that my concrete classes will derive from ABC and set
> _member in their initialization lists to the specific type of
> AnotherABC that the particular class needs.


Can't do that. Instead, ABC needs a (protected) constructor that sets
member, and the derived class can call that constructor.

> However, this can't be done
> as the constructors of the derived classes complain about there being
> no default constructor for ABC.


It won't if you follow the above advice.

> Should I simply replace the reference with a const pointer, or should I
> rethink this and save myself from a potentially nasty design flaw? Is
> there a design pattern I could use here?


I've given you code below:

class Other;

class Base {
Other& other_; // this is private
protected:
virtual ~Base() = 0;
Base(Other& o) : other_(o) {}
};

Base::~Base() {}

class Derived : public Base {
public:
Derived(Other& o) : Base(o) {}
};

Best regards,

Tom

 
Reply With Quote
 
 
 
 
anongroupaccount@googlemail.com
Guest
Posts: n/a
 
      12-10-2005

Thomas Tutone wrote:
> wrote:
> > I have an ABC with a protected member that is a reference to an object
> > of an ABC type:
> >
> > class ABC
> > {
> > public:
> > virtual ~ABC() = 0;

>
> your destructor should be protected, not public.


Why is that? I can understand the constructor being protected, but not
the destructor. Won't this mean that delete won't be able to call the
destructors of inherited classes through the ABC interface?

>
> > protected:

>
>
> your data member should be private, not protected.
>
> > AnotherABC& _member;
> > }


Why? Must I use access methods in my derived classes when one of the
main points of the ABC is to provide a generalized declaration for my
data members in the class hierarchy? Is it inadvisable to have
protected data at all?

>
>
> > The idea is that my concrete classes will derive from ABC and set
> > _member in their initialization lists to the specific type of
> > AnotherABC that the particular class needs.

>
> Can't do that. Instead, ABC needs a (protected) constructor that sets
> member, and the derived class can call that constructor.
>
> > However, this can't be done
> > as the constructors of the derived classes complain about there being
> > no default constructor for ABC.

>
> It won't if you follow the above advice.
>
> > Should I simply replace the reference with a const pointer, or should I
> > rethink this and save myself from a potentially nasty design flaw? Is
> > there a design pattern I could use here?

>
> I've given you code below:
>
> class Other;
>
> class Base {
> Other& other_; // this is private
> protected:
> virtual ~Base() = 0;
> Base(Other& o) : other_(o) {}
> };
>
> Base::~Base() {}
>
> class Derived : public Base {
> public:
> Derived(Other& o) : Base(o) {}
> };
>
> Best regards,
>
> Tom


Thanks for your help, Tom. I hope my questions don't seem too stupid.

 
Reply With Quote
 
Bob Hairgrove
Guest
Posts: n/a
 
      12-10-2005
On 10 Dec 2005 12:49:47 -0800, ""
<> wrote:

>I have an ABC with a protected member that is a reference to an object
>of an ABC type:
>
>class ABC
>{
>public:
> virtual ~ABC() = 0;
>protected:
> AnotherABC& _member;


You shouldn't use names with a leading underscore for anything (see
17.4.3.1.2 of the C++ standard).

>}
>
>The idea is that my concrete classes will derive from ABC and set
>_member in their initialization lists to the specific type of
>AnotherABC that the particular class needs. However, this can't be done
>as the constructors of the derived classes complain about there being
>no default constructor for ABC.
>
>Should I simply replace the reference with a const pointer, or should I
>rethink this and save myself from a potentially nasty design flaw? Is
>there a design pattern I could use here?


What Thomas said ... however, if the member is to be derived from ABC,
you will probably want to store a reference to ABC and not AnotherABC,
relying on the interface defined in ABC for whatever you need to do
with it. As it is, you cannot initialize this member with an object of
type YetAnotherABC, for example, even if that class also derives from
ABC.

--
Bob Hairgrove

 
Reply With Quote
 
red floyd
Guest
Posts: n/a
 
      12-10-2005
wrote:
> I have an ABC with a protected member that is a reference to an object
> of an ABC type:
>
> class ABC
> {
> public:
> virtual ~ABC() = 0;
> protected:
> AnotherABC& _member;
> }
>
> The idea is that my concrete classes will derive from ABC and set
> _member in their initialization lists to the specific type of
> AnotherABC that the particular class needs. However, this can't be done
> as the constructors of the derived classes complain about there being
> no default constructor for ABC.
>
> Should I simply replace the reference with a const pointer, or should I
> rethink this and save myself from a potentially nasty design flaw? Is
> there a design pattern I could use here?
>


What's wrong with:

class AnotherABC;
class ABC
{
public:
virtual ~ABC() = 0;
protected:
ABC(AnotherABC& param) : _member(param) { }
AnotherABC& _member;
};
 
Reply With Quote
 
Thomas Tutone
Guest
Posts: n/a
 
      12-10-2005

wrote:
> Thomas Tutone wrote:
> > wrote:
> > > I have an ABC with a protected member that is a reference to an object
> > > of an ABC type:
> > >
> > > class ABC
> > > {
> > > public:
> > > virtual ~ABC() = 0;

> >
> > your destructor should be protected, not public.

>
> Why is that? I can understand the constructor being protected, but not
> the destructor. Won't this mean that delete won't be able to call the
> destructors of inherited classes through the ABC interface?


Perhaps you are missing the point. ABC's destructor will never be
called directly - because the destructor is virtual, it will be the
destructor of the derived class that will be called, which will in turn
call the base destructor. The derived destructor has access to the
protected functions of its parent.

> > > protected:

> >
> >
> > your data member should be private, not protected.
> >
> > > AnotherABC& _member;
> > > }

>
> Why? Must I use access methods in my derived classes when one of the
> main points of the ABC is to provide a generalized declaration for my
> data members in the class hierarchy?


Typically, yes.

> Is it inadvisable to have
> protected data at all?


Typically yes. To quote Stroustrup: "declaring data members protected
is usually a design error." The C++ Programming Language (3rd ed.)
sec. 15.3.1.1

There are exceptions, but that's the usual rule. If your accessor is
inline, there is typically no overhead to using the accessor.
>
> >
> >
> > > The idea is that my concrete classes will derive from ABC and set
> > > _member in their initialization lists to the specific type of
> > > AnotherABC that the particular class needs.

> >
> > Can't do that. Instead, ABC needs a (protected) constructor that sets
> > member, and the derived class can call that constructor.
> >
> > > However, this can't be done
> > > as the constructors of the derived classes complain about there being
> > > no default constructor for ABC.

> >
> > It won't if you follow the above advice.
> >
> > > Should I simply replace the reference with a const pointer, or should I
> > > rethink this and save myself from a potentially nasty design flaw? Is
> > > there a design pattern I could use here?

> >
> > I've given you code below:
> >
> > class Other;
> >
> > class Base {
> > Other& other_; // this is private
> > protected:
> > virtual ~Base() = 0;
> > Base(Other& o) : other_(o) {}


You are correct - you need an accessor here. E.g.:

void doAction() { other.doAction(); }

or

const Other& other() const { return other_; }

or whatever... It's not clear (to me, anyway) what you are trying to
do.

> > };
> >
> > Base::~Base() {}
> >
> > class Derived : public Base {
> > public:
> > Derived(Other& o) : Base(o) {}
> > };
> >


> Thanks for your help, Tom. I hope my questions don't seem too stupid.


You're welcome, and they're not stupid. You might consider picking up
a copy of Effective C++ (3d ed.), which includes a lot of good advice.

Best regards,

Tom

 
Reply With Quote
 
anongroupaccount@googlemail.com
Guest
Posts: n/a
 
      12-10-2005

Thomas Tutone wrote:
> wrote:
> > Thomas Tutone wrote:
> > > wrote:
> > > > I have an ABC with a protected member that is a reference to an object
> > > > of an ABC type:
> > > >
> > > > class ABC
> > > > {
> > > > public:
> > > > virtual ~ABC() = 0;
> > >
> > > your destructor should be protected, not public.

> >
> > Why is that? I can understand the constructor being protected, but not
> > the destructor. Won't this mean that delete won't be able to call the
> > destructors of inherited classes through the ABC interface?

>
> Perhaps you are missing the point. ABC's destructor will never be
> called directly - because the destructor is virtual, it will be the
> destructor of the derived class that will be called, which will in turn
> call the base destructor. The derived destructor has access to the
> protected functions of its parent.


Okay, but I want to use ABC as an interface. For example:

ABC* inst = new SomeDerivedClass();
delete inst; // I can't delete it, ABC's destructor is protected

I'm sure this isn't an unusual thing to do, which is why I don't
understand having a protected destructor in ABC.

 
Reply With Quote
 
Bob Hairgrove
Guest
Posts: n/a
 
      12-10-2005
On 10 Dec 2005 13:29:14 -0800, "Thomas Tutone"
<> wrote:

>Perhaps you are missing the point. ABC's destructor will never be
>called directly - because the destructor is virtual, it will be the
>destructor of the derived class that will be called, which will in turn
>call the base destructor. The derived destructor has access to the
>protected functions of its parent.


This is not true. If the base class' destructor is protected, clients
using the classes will not be able to call delete on a pointer to the
base class. They will, however, be able to call delete on pointers to
the derived classes.

There are situations where this is the desired behavior, e.g. when a
virtual destructor is not desirable or needed, as with private
inheritance.

--
Bob Hairgrove

 
Reply With Quote
 
Thomas Tutone
Guest
Posts: n/a
 
      12-10-2005

wrote:
> Thomas Tutone wrote:
> > wrote:
> > > Thomas Tutone wrote:
> > > > wrote:
> > > > > I have an ABC with a protected member that is a reference to an object
> > > > > of an ABC type:
> > > > >
> > > > > class ABC
> > > > > {
> > > > > public:
> > > > > virtual ~ABC() = 0;
> > > >
> > > > your destructor should be protected, not public.
> > >
> > > Why is that? I can understand the constructor being protected, but not
> > > the destructor. Won't this mean that delete won't be able to call the
> > > destructors of inherited classes through the ABC interface?

> >
> > Perhaps you are missing the point. ABC's destructor will never be
> > called directly - because the destructor is virtual, it will be the
> > destructor of the derived class that will be called, which will in turn
> > call the base destructor. The derived destructor has access to the
> > protected functions of its parent.

>
> Okay, but I want to use ABC as an interface. For example:
>
> ABC* inst = new SomeDerivedClass();
> delete inst; // I can't delete it, ABC's destructor is protected


Not true. When you call "delete inst," what does the compiler insert
code to do? Well, first, it calls the destructor for inst. Now inst is
declared as a pointer to ABC. ABC has a virtual destructor. So
instead of calling the destructor for an ABC, the compiler inserts code
to call the destructor for SomeDerivedClass, which presumably has a
_public_ destructor. SomeDerivedClass, in turn, calls ABC's
destructor, which SomeDerivedClass is entitled to do, because its
parent is ABC, and a derived class can call a protected function in its
parent. So your example will work fine, nothwithstanding your comment.

> I'm sure this isn't an unusual thing to do, which is why I don't
> understand having a protected destructor in ABC.


I hope this makes sense now. If it doesn't, you need to re-review the
concept of virtual functions.

Best regards,

Tom

 
Reply With Quote
 
Thomas Tutone
Guest
Posts: n/a
 
      12-10-2005

Thomas Tutone wrote:
> wrote:
> > Thomas Tutone wrote:
> > > wrote:
> > > > Thomas Tutone wrote:
> > > > > wrote:
> > > > > > I have an ABC with a protected member that is a reference to an object
> > > > > > of an ABC type:
> > > > > >
> > > > > > class ABC
> > > > > > {
> > > > > > public:
> > > > > > virtual ~ABC() = 0;
> > > > >
> > > > > your destructor should be protected, not public.
> > > >
> > > > Why is that? I can understand the constructor being protected, but not
> > > > the destructor. Won't this mean that delete won't be able to call the
> > > > destructors of inherited classes through the ABC interface?
> > >
> > > Perhaps you are missing the point. ABC's destructor will never be
> > > called directly - because the destructor is virtual, it will be the
> > > destructor of the derived class that will be called, which will in turn
> > > call the base destructor. The derived destructor has access to the
> > > protected functions of its parent.

> >
> > Okay, but I want to use ABC as an interface. For example:
> >
> > ABC* inst = new SomeDerivedClass();
> > delete inst; // I can't delete it, ABC's destructor is protected

>
> Not true. When you call "delete inst," what does the compiler insert
> code to do? Well, first, it calls the destructor for inst. Now inst is
> declared as a pointer to ABC. ABC has a virtual destructor. So
> instead of calling the destructor for an ABC, the compiler inserts code
> to call the destructor for SomeDerivedClass, which presumably has a
> _public_ destructor. SomeDerivedClass, in turn, calls ABC's
> destructor, which SomeDerivedClass is entitled to do, because its
> parent is ABC, and a derived class can call a protected function in its
> parent. So your example will work fine, nothwithstanding your comment.
>


You know what - I'm having a bad day. You are absolutely right and I
am wrong. My apologies for confusing the issue. The destructor should
indeed be public. Glad you're awake, even if I'm not.

Best regards,

Tom

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
references and composition Nick Valeontis C++ 4 11-15-2009 03:40 PM
override when using object composition Tony Johansson C++ 1 09-03-2005 11:11 AM
Difference between bin and obj directories and difference between project references and dll references jakk ASP .Net 4 03-22-2005 09:23 PM
Object Composition & Returning References.... Patrick C++ 4 02-26-2004 02:56 PM
Pointers and References (and References to Pointers) Roger Leigh C++ 8 11-17-2003 10:14 AM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57