Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Private virtual functions

2 views
Skip to first unread message

een...@electeng.leeds.ac.uk

unread,
Nov 10, 2000, 3:00:00 AM11/10/00
to
I read recently on a web-site, and have heard mentioned on here a
few times, that it is sometimes (or always?) useful to make
virtual functions private.

Initially I wondered *why* this would be useful at all, since
if a function was private in the base class then it could not
be seen in the derived class, to be able to override it. The
page I found on a web search (hope this doesn't split to badly)
[pcroot.cern.ch/TaligentDocs/TaligentOnline/DocumentRoot/1.0/Docs/books/WM/
WM_132.html]
notes that in C++ the access modifiers (private/public/protected)
enforce only that: access. Visibility is unaffected?

This style might be relevant for a current situation I'm in, where
a class (and its children) are 'late constructed', for want of a
better description. This is since separate objects become doubly
linked and rather than relying on the user to explicitly make
this link, it is called in the function which constructs the first
link (links as in linked-list meaning).

What I have been doing is making the SetInitialState function
which constructs the backward-link virtual, to enable derived
classes to initialise their extra members once the back-link is
established.

One problem with this is that the base-class SetInitialState must
be called from the derived class version, which could be missed
accidentally. In addition these functions can be called from the
derived classes, which exposes some functionality which is not
necessary?

Could this be solved using something like the following?

class Base
{
public:
SetInitialState(State &SomeState)
: // some initialisation
{ // some more initialisation
StateSetter(SomeState);
}
private:
virtual void StateSetter(State &S) = 0;
}

Then classes derived from Base define their own StateSetter
function, which they cannot call.

These seems like an excellent idea; does it have a name (as in
design pattern)? Can it be applied in other situations -
especially if some say that *all* virtual functions should be
private, and why is this applicable? Don't you end up with
double the number of function names (where virtual), or is there
a way around this?

Is it that it enables use of 'templates' (not the c++ meaning) for
functions to be used? Again, a principle so that derived class
functions need not explicitly call the always-used 'utility'
functions provided by the base-class if they are used in the same
layout/order each time.

Many thanks for your comments,

--
Neil

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]


Gerhard Menzl

unread,
Nov 14, 2000, 3:00:00 AM11/14/00
to
een...@electeng.leeds.ac.uk wrote:

> I read recently on a web-site, and have heard mentioned on here a
> few times, that it is sometimes (or always?) useful to make
> virtual functions private.

It depends on what camp you are in. There have been extensive
discussions on this here, and people seem to be very divided about the
issue. I have identified at least five camps:

1. You can do what? You're kidding me!
2. Okay, I know you can do it, but no honest programmer would. It is
immoral and a disgrace to the profession.
3. You can do it, and you should because it is a great tool that helps
you to fine-tune access levels and maximize encapsulation. Make it
private in the base class and public in the derived class, or the
other way round, whatever meets your design needs.
4. Virtual functions should always be private, never public. Use
non-virtual public wrappers.
5. Virtual functions should always be protected, never public. This
camp is run and populated by James Kanze. <g>

I used to belong to camp 3, but I see the point of the camp 4 people.

There is an excellent article, "Virtually Yours", by Jim Hyslop and Herb
Sutter (camp 4) at:

http://cuj.com/experts/1812/hyslop.html

> Initially I wondered *why* this would be useful at all, since
> if a function was private in the base class then it could not
> be seen in the derived class, to be able to override it. The
> page I found on a web search (hope this doesn't split to badly)

> pcroot.cern.ch/TaligentDocs/TaligentOnline/DocumentRoot/1.0/Docs/
> books/WM/WM_132.html]
> notes that in C++ the access modifiers (private/public/protected)
> enforce only that: access. Visibility is unaffected?

Yes. Overriding and access level are completely orthogonal in C++

> What I have been doing is making the SetInitialState function
> which constructs the backward-link virtual, to enable derived
> classes to initialise their extra members once the back-link is
> established.
>
> One problem with this is that the base-class SetInitialState must
> be called from the derived class version, which could be missed
> accidentally. In addition these functions can be called from the
> derived classes, which exposes some functionality which is not
> necessary?
>
> Could this be solved using something like the following?
>
> class Base
> {
> public:
> SetInitialState(State &SomeState)
>: // some initialisation
> { // some more initialisation
> StateSetter(SomeState);
> }
> private:
> virtual void StateSetter(State &S) = 0;
> }
>
> Then classes derived from Base define their own StateSetter
> function, which they cannot call.

But of course they can. A class always has access to its own member
functions. What a class derived from Base cannot do is to call
Base::StateSetter(), even if it has an implementation.



> These seems like an excellent idea; does it have a name (as in
> design pattern)?

This looks very much like the Template Method pattern to me, but it
seems a bit quirky (although not impossible) that the template method is
called from the derived class. The flow of control bounces up and down
the inheritance hierarchy. I don't say this must never, ever happen, but
I am usually rather suspicious about such yo-yo code. I'm afraid it is
not clear enough to me what you want to achieve, though.

> Can it be applied in other situations -
> especially if some say that *all* virtual functions should be
> private, and why is this applicable? Don't you end up with
> double the number of function names (where virtual), or is there
> a way around this?

If you adhere strictly to what the camp 4 people say, you need double
the number of function names. There is a de facto naming convention that
prefixes the private virtual function with a "do", e.g.:

class Shape
{
public:
void Draw () { DoDraw (); }

private:
virtual void DoDraw () = 0;
};

Gerhard Menzl

James Kanze

unread,
Nov 15, 2000, 3:00:00 AM11/15/00
to
Gerhard Menzl wrote:

> 5. Virtual functions should always be protected, never public. This
> camp is run and populated by James Kanze. <g>

Actually: my position came about as a result of a sort of a challenge,
in this group, to implement Eiffel like pre- and post-condition
checking in C++. My original schema used private virtual functions;
the person posting the challenge pointed out the ways it was different
from the Eiffel checks. One of the ways is that when a derived class
calls the function in Eiffel, the checks are NOT enforced -- within a
member function, invariants, etc., may temporarily be broken.

I'm actually of two minds about this. I think that there are
legitimate arguments both ways. But since no one else seems to want
to defend the protected point of view at present...

While I may be the only one speaking at present, obviously, someone
else feels, or felt, the same way in the past. See std::streambuf,
for example, or any of the facets in <locale>.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

usele...@my-deja.com

unread,
Nov 15, 2000, 3:00:00 AM11/15/00
to
Thank you for pointing out this fresh approach to a persistent
problem. Having all virtual functions private along with some way of
forbidding overriding of non-virtuals just might be the way to go to
control the unstructured computed-goto-like dark side of inheritance.

I have read the recommended "camp 4" article and they do NOT say all
functions should be wrapped in this way, though they do recommend it as
a default. A case where such a wrapper would be a waste is often seen
in user interface programming, where the GUI calls an empty "hook"
method that may be overridden by any derived class.

Having said all this, I've implemented code with the private virtual
functions as the original poster described and was not happy with the
result. The situation was much more complex than that he describes and
the yo-yo effect was definitely confusing. The requirement that the
parameters of the virtual be the same for all classes proved irksome as
well. For the simpler application that the original poster has it
seems appropriate, though, as the goal is to make certain that the
precondition is met. In my case, simply requiring that descendants
call the pre and post condition code would have resulted in more
maintainable code.

In article <3A11144A...@sea.ericsson.se>,


Gerhard Menzl <gerhar...@sea.ericsson.se> wrote:
> een...@electeng.leeds.ac.uk wrote:
>
> > I read recently on a web-site, and have heard mentioned on here a
> > few times, that it is sometimes (or always?) useful to make
> > virtual functions private.
>
> It depends on what camp you are in. There have been extensive
> discussions on this here, and people seem to be very divided about the
> issue. I have identified at least five camps:
>
> 1. You can do what? You're kidding me!
> 2. Okay, I know you can do it, but no honest programmer would. It is
> immoral and a disgrace to the profession.
> 3. You can do it, and you should because it is a great tool that
helps
> you to fine-tune access levels and maximize encapsulation. Make it
> private in the base class and public in the derived class, or the
> other way round, whatever meets your design needs.
> 4. Virtual functions should always be private, never public. Use
> non-virtual public wrappers.

> 5. Virtual functions should always be protected, never public. This
> camp is run and populated by James Kanze. <g>
>


Sent via Deja.com http://www.deja.com/
Before you buy.

een...@electeng.leeds.ac.uk

unread,
Mar 24, 2001, 9:44:57 AM3/24/01
to
Gerhard Menzl <gerhar...@sea.ericsson.se> wrote:
> een...@electeng.leeds.ac.uk wrote:
>
>> I read recently on a web-site, and have heard mentioned on here a
>> few times, that it is sometimes (or always?) useful to make
>> virtual functions private.

[Snip various points of view ('camps') regarding this]

> There is an excellent article, "Virtually Yours", by Jim Hyslop and Herb
> Sutter (camp 4) at:

> http://cuj.com/experts/1812/hyslop.html

Thanks for the reference - this is indeed a good reference. Your mention of
'template method' made me look it up in my GoF book - now I understand it!

Would I be correct in assuming that when implementing a function in a derived
class that the access privelige can vary, and specifies the access of the
*derived* function?

[snip]

[two-way linking as an example of a use for 'template methods']

>> Could this be solved using something like the following?
>>
>> class Base
>> {
>> public:
>> SetInitialState(State &SomeState)
>>: // some initialisation
>> { // some more initialisation
>> StateSetter(SomeState);
>> }
>> private:
>> virtual void StateSetter(State &S) = 0;
>> }
>>
>> Then classes derived from Base define their own StateSetter
>> function, which they cannot call.

> But of course they can. A class always has access to its own member
> functions. What a class derived from Base cannot do is to call
> Base::StateSetter(), even if it has an implementation.

Ah, of course.

>> These seems like an excellent idea; does it have a name (as in
>> design pattern)?

> This looks very much like the Template Method pattern to me, but it
> seems a bit quirky (although not impossible) that the template method is
> called from the derived class. The flow of control bounces up and down
> the inheritance hierarchy. I don't say this must never, ever happen, but
> I am usually rather suspicious about such yo-yo code. I'm afraid it is
> not clear enough to me what you want to achieve, though.

As far as I can tell I do indeed want the template method pattern.

>> Can it be applied in other situations -
>> especially if some say that *all* virtual functions should be
>> private, and why is this applicable? Don't you end up with
>> double the number of function names (where virtual), or is there
>> a way around this?

> If you adhere strictly to what the camp 4 people say, you need double
> the number of function names. There is a de facto naming convention that
> prefixes the private virtual function with a "do", e.g.:

> class Shape
> {
> public:
> void Draw () { DoDraw (); }

> private:
> virtual void DoDraw () = 0;
> };

As in the GoF book - Ta!

With respect to control flow 'bouncing' up and down the inheritance
hierarchy, I presume you mean that you should replace code such as:

class AShape{
public:
virtual void Log(const char *FileName) = 0;
protected:
FILE* f;
void DoOpenStuff(void){\\...};
void DoCloseStuff(void){\\...};
};

class CShape : public AShape{
public:
void Log(const char *FileName){
AShape::DoOpenStuff();
fprintf(f,"Some string\n");
AShape::DoCloseStuff();
}
};

// plus more classes like CShape

with something like:

class AShape{
public:
void Log(const char *FileName){
DoOpenStuff();
LogData(f);
DoCloseStuff();
}
private:
FILE* f;
void DoOpenStuff(void);
void DoCloseStuff(void);
virtual void LogData(FILE *f) = 0;
};

class CShape : public AShape{
private:
void LogData(FILE *f){ fprintf(f,"Some string\n");}
};

// again, same in other classes

This avoids the need for duplicate specification of the algorithm
to run for each concrete shape - ie. just the template method pattern.
The algorithm is enforced as being the same for each class, which if
it was in the previous version and is likely to always be, then is a good
idea.

What I've been thinking about recently is a way of changing the algorithm
in the derived classes:

class AShape{
public:
void Log(const char *FileName){DoLog(FileName);}
private:
virtual void DoLog(const char *FileName){
FILE *f;
// Open file
DoLogging(FileName,f);
// Close file
}
virtual void DoLogging(const char *FileName, FILE *f) = 0;
};

class CRectangle : public AShape{
private:
void DoLogging(const char *FileName, FILE *f){
fprintf(f,"Some string\n");
}
};

Then the default algorithm uses the standard Logging mechanism,
but I could also have:

class CRectangle_LoggedDifferently : public CRectangle{
public:
SetLoggingStatus(bool OnOff);
private:
bool LoggingStatus;
void DoLog(const char *FileName){
if(LoggingStatus){
FILE *f;
// Open file
DoLogging(FileName,f);
// Close file
}
}
};

Rather than having to specify the 'DoLog' algorithm multiple times
(ie. derive from each defaultly-logged class, like CShape), then
use MI, with DoLog specified in one set of classes and DoLogging
specified in another. Then I could just do:

class CRectangle_LoggedDifferently : public CRectangle, CLoggedDifferently{};

I've not done much MI, so this might be incorrect syntactically, and I
probably need some virtual inheritance in there somewhere. However, is
this approach a reasonable one?

Thanks,

--
Neil

Gerhard Menzl

unread,
Mar 26, 2001, 4:34:18 PM3/26/01
to
That reply took quite some time - have you been circumnavigating the
globe or something? <g>

> Would I be correct in assuming that when implementing a function in a
> derived class that the access privelige can vary, and specifies the
> access of the *derived* function?

Yes. Access level and overriding are completely independent. The former
always specifies who is allowed to use (in the case of a function: call)
a member, and the latter invokes an invisible flow of control, i.e. a
call which the compiler performs behind the scenes.

Deriving publicly from a concrete class is not recommended (see Scott
Meyers' "More Effective C++", Item 33) for a detailed explanation. If
you want shapes that always log and shapes for which logging can be
switched on and off, you might try something like:

class AShape
{
public:
void Log (const char* fileName)
{
if (IsLoggingOn () )
DoLog (fileName);
}

private:
virtual void DoLog (const char* fileName) = 0;

// default implementation for derived classes which always log
virtual bool IsLoggingOn () { return true; }
};

class RectangleThatAlwaysLogs : public AShape
{
private:
// don't override IsLoggingOn - use default implementation
virtual void DoLog (const char* fileName) { /*...*/ }
};

class ConifgurableRectangle : public AShape
{
public:
SetLoggingStatus (bool loggingOn);

private:
virtual bool IsLoggingOn () { return loggingStatus; }
virtual void DoLog (const char* fileName) { /*...*/ }

bool loggingStatus;
};

> Rather than having to specify the 'DoLog' algorithm multiple times
> (ie. derive from each defaultly-logged class, like CShape), then
> use MI, with DoLog specified in one set of classes and DoLogging
> specified in another. Then I could just do:
>
> class CRectangle_LoggedDifferently : public CRectangle,
> CLoggedDifferently{};
>
> I've not done much MI, so this might be incorrect syntactically, and
> I probably need some virtual inheritance in there somewhere. However,
> is this approach a reasonable one?

I don't think multiple inheritance is needed here. I only use it when I
want a class to implement different abstract interfaces; therefore I
never need virtual inheritance.

Gerhard Menzl

James Kanze

unread,
Mar 27, 2001, 10:03:50 AM3/27/01
to
Gerhard Menzl wrote:

> > Would I be correct in assuming that when implementing a function
> > in a derived class that the access privelige can vary, and
> > specifies the access of the *derived* function?

> Yes. Access level and overriding are completely independent. The
> former always specifies who is allowed to use (in the case of a
> function: call) a member, and the latter invokes an invisible flow
> of control, i.e. a call which the compiler performs behind the
> scenes.

It's worth pointing out, however, that access control is always on the
*static* type of the expression. Declaring a virtual function private
in a derived class is perfectly legal, but won't prevent anyone from
calling it through a pointer or a reference to the base class. This
may lead to some confusion, and I generally avoid tightening the
access rights in the derived class.

But his AShape isn't a concrete class, it's an abstract base class.
Instrumentation code (pre- and post-condition checks, tracing and
logging, etc.) are typical of the type of code that I expect to find
in an abstract base class, since it is code which is supporting the
contractual interface, and not the implementation. (Typically, the
log destination and controlling parameters will be either static
member or global variables, so typically the class will still not
contain any data members. But there are obviously cases where this
will not be the case.)

This is a standard technique, called mix-ins.

> I don't think multiple inheritance is needed here. I only use it
> when I want a class to implement different abstract interfaces;
> therefore I never need virtual inheritance.

Yes and no. You generally don't want multiple instances of the
abstract base class either, so virtual inheritance might be in order.
I tend to use virual inheritance exclusively once a hierarchy is
"open", that is, once it is designed for client code to derive
arbitrarily from it. (But very few hierarchies are really that open.)

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

Gerhard Menzl

unread,
Mar 28, 2001, 4:01:14 PM3/28/01
to
James Kanze wrote:

> It's worth pointing out, however, that access control is always on
> the *static* type of the expression. Declaring a virtual function
> private in a derived class is perfectly legal, but won't prevent
> anyone from calling it through a pointer or a reference to the base
> class.

Providing anyone can get a pointer or reference to the base class. With
private inheritance, only selected clients can.

> This may lead to some confusion, and I generally avoid tightening
> the access rights in the derived class.

I think we've been there. Would you mind if I refrain from starting the
should-virtual-functions-always-be-private-or-protected debate again?
<g>

> > Deriving publicly from a concrete class is not recommended (see
> > Scott Meyers' "More Effective C++", Item 33) for a detailed
> > explanation. If you want shapes that always log and shapes for
> > which logging can be switched on and off, you might try something
> > like:
>
> But his AShape isn't a concrete class, it's an abstract base class.

I was referring to his CRectangle_LoggedDifferently deriving from
CRectangle, which is a concrete class.

> > I don't think multiple inheritance is needed here. I only use it
> > when I want a class to implement different abstract interfaces;
> > therefore I never need virtual inheritance.
>
> Yes and no. You generally don't want multiple instances of the
> abstract base class either, so virtual inheritance might be in order.

Of course. Personally, however, I have never created a class hierarchy
where two abstract base classes were derived themselves from a common
abstract ancestor.

Gerhard Menzl

James Kanze

unread,
Mar 29, 2001, 2:37:08 PM3/29/01
to
Gerhard Menzl wrote:

> > > I don't think multiple inheritance is needed here. I only use it
> > > when I want a class to implement different abstract interfaces;
> > > therefore I never need virtual inheritance.

> > Yes and no. You generally don't want multiple instances of the
> > abstract base class either, so virtual inheritance might be in
> > order.

> Of course. Personally, however, I have never created a class
> hierarchy where two abstract base classes were derived themselves
> from a common abstract ancestor.

Quite true. The case isn't frequent. Perhaps the rule should be: if
a class is abstract, all of its bases should be inherited virtually.
Most of the time, of course, if the class is abstract, it won't have
bases, so the rule is a no-op, but it may avoid problems in the other
cases.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

Atgeirr F Rasmussen

unread,
Mar 30, 2001, 2:56:54 PM3/30/01
to
[snip]

>
> > Of course. Personally, however, I have never created a class
> > hierarchy where two abstract base classes were derived themselves
> > from a common abstract ancestor.
>
> Quite true. The case isn't frequent. Perhaps the rule should be: if
> a class is abstract, all of its bases should be inherited virtually.
> Most of the time, of course, if the class is abstract, it won't have
> bases, so the rule is a no-op, but it may avoid problems in the other
> cases.

I don't quite understand this. Does this mean that you only rarely use
class hierarchies with three or more levels? I assume that you do not
inherit (at least not very often) from non-abstract classes. I use
3-level hierarchies quite often, and then I use two abstract levels and
one concrete level.

Atgeirr F Rasmussen

Gerhard Menzl

unread,
Mar 31, 2001, 4:38:55 AM3/31/01
to
James Kanze wrote:

> > Of course. Personally, however, I have never created a class
> > hierarchy where two abstract base classes were derived themselves
> > from a common abstract ancestor.
>
> Quite true. The case isn't frequent. Perhaps the rule should be: if
> a class is abstract, all of its bases should be inherited virtually.
> Most of the time, of course, if the class is abstract, it won't have
> bases, so the rule is a no-op, but it may avoid problems in the other
> cases.

I think it's too rigid as it stands. In OO framework design, I often
arrive at something like:

+-----------------+
| pure abstract |
| interface class |
+-----------------+
^
|
+-----------------+
| semi-abstract |
| class with some |
| implementation |
+-----------------+
^
|
+-----------------+
| concrete user |
| class |
+-----------------+

The topmost base would be used only within the framework, while the
middle base is interface for the framework user. Virtual inheritance,
which your rule would require, seems excessive to me here - unless, of
course, there are two or more classes that are designed to be derived
from and derive themselves from a common base. It's really a question of
what the polymorphic interface is like.

Gerhard Menzl

John Potter

unread,
Apr 1, 2001, 2:07:38 PM4/1/01
to
On 28 Mar 2001 16:01:14 -0500, Gerhard Menzl
<gerhar...@sea.ericsson.se> wrote:

> James Kanze wrote:
>
> > It's worth pointing out, however, that access control is always on
> > the *static* type of the expression. Declaring a virtual function
> > private in a derived class is perfectly legal, but won't prevent
> > anyone from calling it through a pointer or a reference to the base
> > class.
>
> Providing anyone can get a pointer or reference to the base class. With
> private inheritance, only selected clients can.

Only those clients whose author knows how to type

Base* pb((Base*)pd); // 5.4/7

Doesn't seem very selective to me. ;)

John

James Kanze

unread,
Apr 2, 2001, 1:10:24 PM4/2/01
to
Atgeirr F Rasmussen wrote:

> [snip]

> > > Of course. Personally, however, I have never created a class
> > > hierarchy where two abstract base classes were derived
> > > themselves from a common abstract ancestor.

> > Quite true. The case isn't frequent. Perhaps the rule should be:
> > if a class is abstract, all of its bases should be inherited
> > virtually. Most of the time, of course, if the class is abstract,
> > it won't have bases, so the rule is a no-op, but it may avoid
> > problems in the other cases.

> I don't quite understand this. Does this mean that you only rarely
> use class hierarchies with three or more levels? I assume that you
> do not inherit (at least not very often) from non-abstract
> classes. I use 3-level hierarchies quite often, and then I use two
> abstract levels and one concrete level.

A lot depends on the application; I've worked on applications where
the average inheritance depth was about 7 or 8. But such applications
are, I think, a minority, and I'd say that globally, about 90% of my
classes don't involve more than two levels: one or more abstract base
classes which define the interface, and a single class which inherits
from them and implements it.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

James Kanze

unread,
Apr 2, 2001, 1:12:07 PM4/2/01
to
Gerhard Menzl wrote:

> James Kanze wrote:

If I understand you correctly, what you are saying is that from the
point of view of the application coder, the semi-abstract class is the
real base, and practically, only the semi-abstract base should inherit
from the pure abstract base. If this is correct, and you can be
certain of it, then, yes, there is no need for virtual inheritance.
But if this is true, and you can be certain of it, there is also no
formal need for the semi-abstract base and the pure abstract interface
to be separate classes.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

Gerhard Menzl

unread,
Apr 2, 2001, 3:31:18 PM4/2/01
to
John Potter wrote:

> > Providing anyone can get a pointer or reference to the base class.
> > With private inheritance, only selected clients can.
>
> Only those clients whose author knows how to type
>
> Base* pb((Base*)pd); // 5.4/7

Or

#define private public

#include "base.h"

for that matter.

> Doesn't seem very selective to me. ;)

Your point being?

Gerhard Menzl

Kevin Cline

unread,
Apr 3, 2001, 10:26:01 AM4/3/01
to
James Kanze <James...@dresdner-bank.com> writes:

> Gerhard Menzl wrote:
>
> > I think it's too rigid as it stands. In OO framework design, I often
> > arrive at something like:
>
> > +-----------------+
> > | pure abstract |
> > | interface class |
> > +-----------------+
> > ^
> > |
> > +-----------------+
> > | semi-abstract |
> > | class with some |
> > | implementation |
> > +-----------------+
> > ^
> > |
> > +-----------------+
> > | concrete user |
> > | class |
> > +-----------------+
>
> > The topmost base would be used only within the framework, while the
> > middle base is interface for the framework user.
>

> If I understand you correctly, what you are saying is that from the
> point of view of the application coder, the semi-abstract class is the
> real base, and practically, only the semi-abstract base should inherit
> from the pure abstract base. If this is correct, and you can be
> certain of it, then, yes, there is no need for virtual inheritance.
> But if this is true, and you can be certain of it, there is also no
> formal need for the semi-abstract base and the pure abstract interface
> to be separate classes.

I agree with James. The reason for splitting the interface from the
partial implementation is so that the implementation can be changed
while the interface remains the same. But this is only useful if
alternate partial implementations are possible. If you provide a
single partial implementation with the framework, without documenting
how to create others, then there is little benefit in separating it
from the interface class.

I avoid structures like this one in application code because
inevitably some one uses the partial implementation for an interface.
Instead I prefer to inherit only the true interface publicly, and to
imherit the implementation privately. This results in a few more
lines of code in the concrete class, but I think it's worthwhile to
cleanly separate interface from implementation.
--
Kevin Cline

James Dennett

unread,
Apr 3, 2001, 6:51:08 PM4/3/01
to
Gerhard Menzl wrote:
>
> John Potter wrote:
>
> > > Providing anyone can get a pointer or reference to the base class.
> > > With private inheritance, only selected clients can.
> >
> > Only those clients whose author knows how to type
> >
> > Base* pb((Base*)pd); // 5.4/7
>
> Or
>
> #define private public
>
> #include "base.h"
>
> for that matter.

The #define is not legal C++, whereas the C-style case is.
AFAIK.

-- James Dennett

John Potter

unread,
Apr 3, 2001, 10:58:31 PM4/3/01
to
On 2 Apr 2001 15:31:18 -0400, Gerhard Menzl
<gerhar...@sea.ericsson.se> wrote:

> John Potter wrote:
>
> > > Providing anyone can get a pointer or reference to the base class.
> > > With private inheritance, only selected clients can.
> >
> > Only those clients whose author knows how to type
> >
> > Base* pb((Base*)pd); // 5.4/7
>
> Or
>
> #define private public

Undefined behavior.

> #include "base.h"
>
> for that matter.
>
> > Doesn't seem very selective to me. ;)
>
> Your point being?

struct B1 { };
struct B2 { };
struct D : private B1, public B2 { };
void f (D* pd) {
B1* pb1((B1*)pd); // standard cast to private base
B2* pb2((B2*)pd); // static_cast, not needed
}

There isn't even any difference in syntax and both are required to
work correctly.

John

Gerhard Menzl

unread,
Apr 5, 2001, 6:35:29 AM4/5/01
to
James Dennett wrote:

> > > > Providing anyone can get a pointer or reference to the base
> > > > class. With private inheritance, only selected clients can.
> > >
> > > Only those clients whose author knows how to type
> > >
> > > Base* pb((Base*)pd); // 5.4/7
> >
> > Or
> >
> > #define private public
> >
> > #include "base.h"
> >
> > for that matter.
>
> The #define is not legal C++, whereas the C-style case is.
> AFAIK.

I am well aware of this. My point was: someone who enforces a conversion
that was meant to remain hidden by using a cast would probably not
hesitate to redefine keywords in order to get at the innards of a class.
That it is possible to subvert the type system doesn't mean it is
useless.

Perhaps I should just have recited the old adage: C++ can protect you
against Murphy, but not against Macchiavelli.

Gerhard Menzl

Gerhard Menzl

unread,
Apr 5, 2001, 6:36:53 AM4/5/01
to
James Kanze wrote:

> If I understand you correctly, what you are saying is that from the
> point of view of the application coder, the semi-abstract class is
> the real base, and practically, only the semi-abstract base should
> inherit from the pure abstract base.

This is correct indeed.

> If this is correct, and you can be certain of it, then, yes, there is
> no need for virtual inheritance. But if this is true, and you can be
> certain of it, there is also no formal need for the semi-abstract base
> and the pure abstract interface to be separate classes.

There can be practical need if, for example, the pure abstract base is
used within the framework as a callback interface that decouples the
semi-abstract descendant and another internally used class:

+-----------------+
| pure abstract | notifies
| observer class |<---------------------+
+-----------------+ |
^ |
| |
+-----------------+ +-----------+
| semi-abstract | subscribes | internal |
| class with some |--------------->| publisher |
| implementation | | class |
+-----------------+ +-----------+


^
|
+-----------------+
| concrete user |
| class |
+-----------------+


Gerhard Menzl

Gerhard Menzl

unread,
Apr 5, 2001, 6:37:10 AM4/5/01
to
Kevin Cline wrote:

> > If I understand you correctly, what you are saying is that from the
> > point of view of the application coder, the semi-abstract class is
> > the real base, and practically, only the semi-abstract base should
> > inherit from the pure abstract base. If this is correct, and you
> > can be certain of it, then, yes, there is no need for virtual
> > inheritance. But if this is true, and you can be certain of it,
> > there is also no formal need for the semi-abstract base and the pure
> > abstract interface to be separate classes.
>
> I agree with James. The reason for splitting the interface from the
> partial implementation is so that the implementation can be changed
> while the interface remains the same. But this is only useful if
> alternate partial implementations are possible. If you provide a
> single partial implementation with the framework, without documenting
> how to create others, then there is little benefit in separating it
> from the interface class.

This is *one* possible reason. As I have pointed out to James in another
posting, another valid reason can be decoupling the partial
implementation and another concrete class in the framework.

> I avoid structures like this one in application code because
> inevitably some one uses the partial implementation for an interface.
> Instead I prefer to inherit only the true interface publicly, and to
> imherit the implementation privately. This results in a few more
> lines of code in the concrete class, but I think it's worthwhile to
> cleanly separate interface from implementation.

In general, I try to avoid implementation inheritance, and I never
inherit publicly for the sole reason of code reuse. However, there are
situations, especially in OO framework design, where beefing up what was
initially designed as an abstract interface with default implementation
turns out to be a lesser evil than the horrendously complex mesh of
relationships that would be incurred by the alternative solution. It's
really a trade-off.

Gerhard Menzl

Raoul Gough

unread,
Apr 5, 2001, 4:16:34 PM4/5/01
to
"John Potter" <jpo...@falcon.lhup.edu> wrote in message
news:3ac924e4...@news.csrlink.net...

> On 2 Apr 2001 15:31:18 -0400, Gerhard Menzl
> <gerhar...@sea.ericsson.se> wrote:
> > > Doesn't seem very selective to me. ;)
> >
> > Your point being?
>
> struct B1 { };
> struct B2 { };
> struct D : private B1, public B2 { };
> void f (D* pd) {
> B1* pb1((B1*)pd); // standard cast to private base
> B2* pb2((B2*)pd); // static_cast, not needed
> }
>
> There isn't even any difference in syntax and both are required to
> work correctly.
>
> John
>

Seems like a good reason not to use C-style casts.

--
Don't bother trying the deja return address. You could try the same username
"at" knuut.de or via Hotmail if I've moved home address.

0 new messages