virtual keyword for the derived class

S

Shao Zhang

Hi,

I am not sure if the virtual keyword for the derived classes are
required given
that the base class already declares it virtual.

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

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

class C: public B
{
public:
virtual ~C();
}

My question is whether I need the virtual keyword for class B and C? If
I don't need it, is it recommanded to always add the virtual keyword?
Does it have any negative effect at all?

Thanks.
Shao.
 
C

Cy Edmunds

Shao Zhang said:
Hi,

I am not sure if the virtual keyword for the derived classes are
required given
that the base class already declares it virtual.

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

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

class C: public B
{
public:
virtual ~C();
}

My question is whether I need the virtual keyword for class B and C? If
I don't need it, is it recommanded to always add the virtual keyword?
Does it have any negative effect at all?

Thanks.
Shao.

It's not required, but I think it's a good idea to declare all virtual
functions explicitly. It makes it a little easier to understand IMHO.
 
S

Siemel Naran

It's not required, but I think it's a good idea to declare all virtual
functions explicitly. It makes it a little easier to understand IMHO.

Often I use comments, though neither way is better than the other.

class X: public Y {
protected: // virtual functions inherited from X
bool equal() const;
};
 
R

Rolf Magnus

Cy said:
It's not required, but I think it's a good idea to declare all virtual
functions explicitly. It makes it a little easier to understand IMHO.

The main point is that you can see that the function is virtual without
having to look into the base class first (or the base's base or the
base's base's base or wherever it was initially declared virtual).
IMHO it would be better if C++ required the virtual keyword in this
place.
 
J

JKop

Shao Zhang posted:
My question is whether I need the virtual keyword for class B and C? If
I don't need it, is it recommanded to always add the virtual keyword?
Does it have any negative effect at all?

Thanks.
Shao.

Yes, put the "virtual" keyword in the derived class. It has
no negative effects whatsoever, only positive ones:

A) You can tell that the function's virtual without having
a look back at the base class.

B) If the base class is changed so that the function's no
longer virtual, then it's *still* virtual in the derived
class and in derived classes of the derived class, and this
is how those classes will have been designed.


-JKop
 
R

Rob Williscroft

Shao Zhang wrote in in
comp.lang.c++:
Hi,

I am not sure if the virtual keyword for the derived classes are
required given
that the base class already declares it virtual.

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

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

class C: public B
{
public:
virtual ~C();
}

My question is whether I need the virtual keyword for class B and C? If
I don't need it, is it recommanded to always add the virtual keyword?
Does it have any negative effect at all?

Contary to other posters in this thread, you should only use
virtual if its a requirment, i.e. is the virtualness of the member
is part of the derived classes interface.

With the example above 'A' has a virtual destructor, this means
that 'A' is a type that can (as a pointer) hold deletable
references to instances of type 'A' or any type derived from it.

Presumably this is a requirment for type 'A'. If it isn't then
virtual shouldn't be there in the first place.

If type 'B' doesn't share this requirment then 'B' shouldn't
impose it.

C++ doesn't make you pay for things you don't use, as a programmer
you shouldn't make youself (or others) pay for things you don't use.

As an example:

#include <iostream>
#include <ostream>
#include <list>

struct base
{
virtual ~base() {}
};

struct container
{
private:

typedef std::list< base * > base_list_t;
std::list< base * > base_list;

public:

~container()
{
base_list_t::iterator
ptr = base_list.begin(),
lim = base_list.end()
;
for (; ptr != lim; ++ptr )
{
delete *ptr;
}
}

void add( base *bp )
{
try
{
base_list.push_back( bp );
}
catch ( ... )
{
delete bp;
throw;
}
}
};


struct derived : base
{
~derived()
{
std::cout << "~derived()\n";
}
};

int main()
{
container c;

c.add( new derived() );
c.add( new derived() );
}

Now refactor using boost::shared_ptr:

http://www.boost.org/libs/smart_ptr/smart_ptr.htm

#include <iostream>
#include <ostream>
#include <list>

#include "boost/shared_ptr.hpp"

struct base
{
};

struct container
{
private:

typedef std::list< base * > base_list_t;
std::list< boost::shared_ptr< base > > base_list;

public:

template < typename T >
void add( T *bp )
{
base_list.push_back( boost::shared_ptr< base >( bp ) );
}
};


struct derived : base
{
~derived()
{
std::cout << "~derived()\n";
}
};

int main()
{
container c;

c.add( new derived() );
c.add( new derived() );
}

In both of the examples 'derived' /inherits/ from 'base' the ability
to be placed (via new) in an instance of 'container'. How 'base' and
'container' meet this requirment is none of the 'derived' types
business.

Rob.
 
R

Richard Herring

Rob said:
Shao Zhang wrote in in
comp.lang.c++:


Contary to other posters in this thread, you should only use
virtual if its a requirment, i.e. is the virtualness of the member
is part of the derived classes interface.

Did you miss the part where he wrote?

As I read it, it's a simple style question about whether the (redundant
to the compiler but a useful clue for human readers) "virtual" keyword
should be repeated in the declarations of subsequent derived classes,
not a philosophical question about whether one should make the base
class polymorphically destructible.
 
J

jeffc

Shao Zhang said:
My question is whether I need the virtual keyword for class B and C? If
I don't need it, is it recommanded to always add the virtual keyword?
Does it have any negative effect at all?

No effect at all. I'd recommend using it merely because it makes people
reading the code later feel more at ease. For example, someone maintaining
class C will look at class B - if they see a virtual keyword in class B,
they don't need to look in class A to figure out if it's virtual.
 
J

jeffc

Rolf Magnus said:
The main point is that you can see that the function is virtual without
having to look into the base class first (or the base's base or the
base's base's base or wherever it was initially declared virtual).
IMHO it would be better if C++ required the virtual keyword in this
place.

But that begs the question: what would it then mean if the keyword were left
off?
 
R

Rob Williscroft

Richard Herring wrote in in
comp.lang.c++:
Did you miss the part where he wrote
?

No I didn't.
As I read it, it's a simple style question about whether the (redundant
to the compiler but a useful clue for human readers) "virtual" keyword
should be repeated in the declarations of subsequent derived classes,

If you're just repeating virtual 'cause "its in the base class" then
you're coupling the derived class to an implementation detail of
the base class.

OTOH if you expect your class to be derived from and want to allow
those derived classes to overide you implementation you should make
the member virtual, but that is independant of wether you've derived
from a base and are overriding yourself.
not a philosophical question about whether one should make the base
class polymorphically destructible.

Indeed, but I never suggested it was, the examples I gave used virtual
destructors (as the OP's did), but any member function would have done.

Rob.
 
J

jeffc

Rob Williscroft said:
Contary to other posters in this thread, you should only use
virtual if its a requirment, i.e. is the virtualness of the member
is part of the derived classes interface.

I think you're missing the point. In subclasses, it's already virtual - you
don't really have a choice.
 
R

Rob Williscroft

jeffc wrote in in comp.lang.c++:
I think you're missing the point. In subclasses, it's already virtual
- you don't really have a choice.

In the second example I gave I rewrote the first so that virtual
wasn't used. There was *no* change to the text of the derived class,
but its destructor was nolonger virtual.

In effect 'base' offered the following contract:

Derive from 'base' and you can put new'd objects in a 'container'.

container c;
c.add( new your_base_derived_type_here );

Both version's met the contract, the first used a virtual destructor
in 'base', the second didn't, unless a derived type has it own *need*
to make a member virtual it shouldn't do so.

Making the derived member virtual just because the base member is
virtual only serves to document a detail of another class, sorry
but I really don't see the point in that.

Rob.
 
K

Karl Heinz Buchegger

Rob said:
In the second example I gave I rewrote the first so that virtual
wasn't used.

I may be missing something, but I think that the second example
you posted is plain and simple illegal.

Obviously you are destroying a derived class object through a
base class pointer. If your code does it or if boost::shared_ptr
does it, doesn't make a difference. It is still: deletion of a derived
class object through a base clasee pointer without a virtual destructor.
 
S

Siemel Naran

The main point is that you can see that the function is virtual without
having to look into the base class first (or the base's base or the
base's base's base or wherever it was initially declared virtual).
IMHO it would be better if C++ required the virtual keyword in this
place.

It is possible the function is not virtual in the base class, but is in the
derived class, so strictly speaking the virtual tells us little other than
the function is virtual in this and further derived classes. It would also
have been nice if C++ prohibited this too, as I've never seen it used.
 
K

Karl Heinz Buchegger

Siemel said:
It is possible the function is not virtual in the base class, but is in the
derived class, so strictly speaking the virtual tells us little other than
the function is virtual in this and further derived classes. It would also
have been nice if C++ prohibited this too, as I've never seen it used.

My personal favourite would have been to have 2 keywords:
one for the 'start of the virtual chain'
one for 'continuation of the virtual chain'

Then the whole things becomes

class Base
{
virtual_start void foo();
};

class Derived
{
virtual_cont void foo();
};

The compiler then could check in the case of virtual_cont that in the Base
class (or the Base of the Base) the very same function is declared virtual_start.
If not -> Error
If on the other hand, the keyword virtual_cont is left out, this could also be
consider to be an error, if the Base class declared this function to be virtual_start

Why?

Because in the real world it happens, that one has to turn a normal function into
a virtual one and vice versa). The consequences of doing that can be dramatic, thus
each class deriving from that class need to checked if the behaviour of that function
is still ok. Currently the compiler has no way to help with doing that. It silently
transforms derived class functions into virtual ones.
 
R

Richard Herring

Rob said:
Richard Herring wrote in in
comp.lang.c++:


No I didn't.


If you're just repeating virtual 'cause "its in the base class" then
you're coupling the derived class to an implementation detail of
the base class.

Ah, well, IMO virtualness of a member function can't be dismissed as an
implementation detail. It's a major declaration of intent about what the
designer of the base class expects to happen when that function gets
called - possibly by code within the base class itself.
OTOH if you expect your class to be derived from and want to allow
those derived classes to overide you implementation you should make
the member virtual, but that is independant of wether you've derived
from a base and are overriding yourself.

I think I see what you're suggesting, but it doesn't work. Conceptually
it would be as though the first derived class marked the override as
"final" and then offered itself as a new "base" with a new virtual
function that just happens to have the same name. The trouble is that
once you've uncorked virtualness it can't be put back in the bottle.
Base code calling the virtual function will get the most derived
version, not the "final" one of the intermediate class.
Indeed, but I never suggested it was, the examples I gave used virtual
destructors (as the OP's did), but any member function would have done.

Same response. Nor was it a philosophical question about whether one
should make the base class polymorphic wrt any member function.
 
R

Rob Williscroft

Karl Heinz Buchegger wrote in in
comp.lang.c++:
I may be missing something,

Yes, its a property of boost::shared_ptr that it handels this case,

template < typename T >
void add( T *bp )
{
base_list.push_back( boost::shared_ptr< base >( bp ) );
}

Note that boost::shared_ptr< base > above is initialized with
the actual type that is being stored, through the magic of
templates the shared_ptr stores a deleter that works with a
derived type.

http://www.boost.org/libs/smart_ptr/shared_ptr.htm#constructors
but I think that the second example
you posted is plain and simple illegal.

Obviously you are destroying a derived class object through a
base class pointer. If your code does it or if boost::shared_ptr
does it, doesn't make a difference. It is still: deletion of a derived
class object through a base clasee pointer without a virtual destructor.

The shared_ptr handles the details, no UB.

Rob.
 
R

Rob Williscroft

Richard Herring wrote in in
comp.lang.c++:
Ah, well, IMO virtualness of a member function can't be dismissed as
an implementation detail. It's a major declaration of intent about
what the designer of the base class expects to happen when that
function gets called - possibly by code within the base class itself.

Yes, but that is a quality of the base class, a derived type shouldn't
(need to) repeat that statement of intent, unless it has a real need,
i.e. it intends to manipulate it virtually itself.
I think I see what you're suggesting, but it doesn't work.
Conceptually it would be as though the first derived class marked the
override as "final" and then offered itself as a new "base" with a new
virtual function that just happens to have the same name. The trouble
is that once you've uncorked virtualness it can't be put back in the
bottle. Base code calling the virtual function will get the most
derived version, not the "final" one of the intermediate class.

If that were possible then derived wouldn't be a base, so inheritance
would be inappropriate.

The derived class *is a* base, anyone further deriving should expect
it to behave like the base and should read the base clases documentation.

Rob.
 
R

Rolf Magnus

Karl said:
My personal favourite would have been to have 2 keywords:
one for the 'start of the virtual chain'
one for 'continuation of the virtual chain'

Then the whole things becomes

class Base
{
virtual_start void foo();
};

class Derived
{
virtual_cont void foo();
};

I'd call them 'virtual' and 'override'. And while we're at it, add
another keyword 'pure' so we can get rid of that strange
"pseudo-inizialize with 0 to make it pure virtual" syntax.
The compiler then could check in the case of virtual_cont that in the
Base class (or the Base of the Base) the very same function is
declared virtual_start. If not -> Error
If on the other hand, the keyword virtual_cont is left out, this could
also be consider to be an error, if the Base class declared this
function to be virtual_start

Why?

Because in the real world it happens, that one has to turn a normal
function into a virtual one and vice versa). The consequences of doing
that can be dramatic, thus each class deriving from that class need to
checked if the behaviour of that function is still ok. Currently the
compiler has no way to help with doing that. It silently transforms
derived class functions into virtual ones.

Yes.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top