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

Inheriting a vector

P: n/a
Hi,
I want to have a vector like class with some additional functionality
(cosmetic one). So can I inherit a vector class to add the addition
function like,

CorresVector : public vector<Corres>{
public:
void addCorres(Corres& c); //it do little more than push_back
function.
}
Or I need to do a composition to do it (i.e storing the vector inside
Corresvector & delegating the necessary functionality). I want to know
that whether in this case (inheriting) is allowed for containers, i.e
will the container will get freed when CorresVector gets destoryed (i.e
vector has a virtual destructor which gets called?)

abir

Sep 26 '06 #1
Share this Question
Share on Google+
24 Replies


P: n/a

toton wrote:
Hi,
I want to have a vector like class with some additional functionality
(cosmetic one). So can I inherit a vector class to add the addition
function like,

CorresVector : public vector<Corres>{
public:
void addCorres(Corres& c); //it do little more than push_back
function.
}
Or I need to do a composition to do it (i.e storing the vector inside
Corresvector & delegating the necessary functionality). I want to know
that whether in this case (inheriting) is allowed for containers, i.e
will the container will get freed when CorresVector gets destoryed (i.e
vector has a virtual destructor which gets called?)
No, vector does not have a virtual destructor. It doesn't have any
virtual functions. You can inherit from a vector but you can't do so
polymorphically.

Sep 26 '06 #2

P: n/a
toton wrote:
Hi,
I want to have a vector like class with some additional functionality
(cosmetic one). So can I inherit a vector class to add the addition
function like,

CorresVector : public vector<Corres>{
public:
void addCorres(Corres& c); //it do little more than push_back
function.
}
Or I need to do a composition to do it (i.e storing the vector inside
Corresvector & delegating the necessary functionality). I want to know
that whether in this case (inheriting) is allowed for containers, i.e
will the container will get freed when CorresVector gets destoryed (i.e
vector has a virtual destructor which gets called?)

abir
Hi abir,

std::vector does not have a virtual destructor.
But it would only need one, if you delete a CorresVector through a pointer
to a base class.

As for the question whether it is the "right" approach, use google and you
will find a lot of different opinions (see e.g.
http://www.thescripts.com/forum/thread63869.html).

Cheers,
Frank


Sep 26 '06 #3

P: n/a

Frank wrote:
toton wrote:
Hi,
I want to have a vector like class with some additional functionality
(cosmetic one). So can I inherit a vector class to add the addition
function like,

CorresVector : public vector<Corres>{
public:
void addCorres(Corres& c); //it do little more than push_back
function.
}
Or I need to do a composition to do it (i.e storing the vector inside
Corresvector & delegating the necessary functionality). I want to know
that whether in this case (inheriting) is allowed for containers, i.e
will the container will get freed when CorresVector gets destoryed (i.e
vector has a virtual destructor which gets called?)

abir

Hi abir,

std::vector does not have a virtual destructor.
But it would only need one, if you delete a CorresVector through a pointer
to a base class.

As for the question whether it is the "right" approach, use google and you
will find a lot of different opinions (see e.g.
http://www.thescripts.com/forum/thread63869.html).
I have a Session class which stores the CorresVector, not a pointer or
reference. and Session class destructor will thus automatically call
CorresVector. Hence there is no ploymorphic behavior. I hope there will
not be any memory leak therefore.
Otherwise it is pain to delegate a lot of method including container
traits & iterators.
Religion is definitely a question, may think later of delegating (or
protected inheritence) if my class sufficiently differs from vector or
any other misuse question comes (I know Java Stack is inherited from
Vector ! ).
Cheers,
Frank
Sep 26 '06 #4

P: n/a

Frank wrote:
toton wrote:
Hi,
I want to have a vector like class with some additional functionality
(cosmetic one). So can I inherit a vector class to add the addition
function like,

CorresVector : public vector<Corres>{
public:
void addCorres(Corres& c); //it do little more than push_back
function.
}
Or I need to do a composition to do it (i.e storing the vector inside
Corresvector & delegating the necessary functionality). I want to know
that whether in this case (inheriting) is allowed for containers, i.e
will the container will get freed when CorresVector gets destoryed (i.e
vector has a virtual destructor which gets called?)

abir

Hi abir,

std::vector does not have a virtual destructor.
But it would only need one, if you delete a CorresVector through a pointer
to a base class.

As for the question whether it is the "right" approach, use google and you
will find a lot of different opinions (see e.g.
http://www.thescripts.com/forum/thread63869.html).
I have a Session class which stores the CorresVector, not a pointer or
reference. and Session class destructor will thus automatically call
CorresVector. Hence there is no ploymorphic behavior. I hope there will
not be any memory leak therefore.
Otherwise it is pain to delegate a lot of method including container
traits & iterators.
Religion is definitely a question, may think later of delegating (or
protected inheritence) if my class sufficiently differs from vector or
any other misuse question comes (I know Java Stack is inherited from
Vector ! ).
Thanks for quick answer.
Cheers,
Frank
Sep 26 '06 #5

P: n/a

toton wrote:
Hi,
I want to have a vector like class with some additional functionality
(cosmetic one). So can I inherit a vector class to add the addition
function like,

CorresVector : public vector<Corres>{
public:
void addCorres(Corres& c); //it do little more than push_back
function.
}
Or I need to do a composition to do it (i.e storing the vector inside
Corresvector & delegating the necessary functionality). I want to know
that whether in this case (inheriting) is allowed for containers, i.e
will the container will get freed when CorresVector gets destoryed (i.e
vector has a virtual destructor which gets called?)

abir
You should not derive from STL container classes. Their destructors are
not virtual.
Although, in my book, composition can be a form of private inheritence.
Why not template the class? In your example, if element class Corres,
whatever that is, overloads the global op<<, you can add features as
shown below. Note that both primitive int and class std::string already
have an overloaded operator<<.

The point here is that if you are going to compose with a std::vector,
do it to add features, otherwise you would not need to wrap the
container.
How you do that is not very complicated:

a) learn how to declare and use templates
b) pass by reference
c) dependant types need the typename keyword
d) overload operators

#include <iostream>
#include <ostream>
#include <string>
#include <vector>

template< typename T >
class Vector
{
std::vector< T vt;
public:
Vector() : vt() { } // an empty vector of TsSince primitive types
like int and other classes like std::string already have an overload
for global op<<, i can iterate through the elements simply by writing:

std::cout << name_of_container;
~Vector() { }
/* member functions */
size_t size() const { return vt.size(); }
void push_back( const T& r_t ) { vt.push_back( r_t ); }
/* friend op */
friend
std::ostream&
operator<<( std::ostream& os, Vector< T >& r_v )
{ // std::vector<T>::iterator is a dependant type
typedef typename std::vector< T >::iterator VIter;
VIter iter = r_v.vt.begin();
for ( iter; iter != r_v.vt.end(); ++iter )
{
os << *iter << std::endl;
}
return os;
}
};

int main()
{
Vector< int integers;
for ( int n = 0; n < 5; ++n )
{
integers.push_back( n );
}
std::cout << integers; // op<< overload

Vector< std::string strings;
strings.push_back( "first string" );
strings.push_back( "second string" );
strings.push_back( "third string" );
strings.push_back( "fourth string" );
std::cout << strings; // op<< overload

return 0;
}

/*
0
1
2
3
4
first string
second string
third string
fourth string
*/

Sep 26 '06 #6

P: n/a

Salt_Peter wrote:
toton wrote:
Hi,
I want to have a vector like class with some additional functionality
(cosmetic one). So can I inherit a vector class to add the addition
function like,

CorresVector : public vector<Corres>{
public:
void addCorres(Corres& c); //it do little more than push_back
function.
}
Or I need to do a composition to do it (i.e storing the vector inside
Corresvector & delegating the necessary functionality). I want to know
that whether in this case (inheriting) is allowed for containers, i.e
will the container will get freed when CorresVector gets destoryed (i.e
vector has a virtual destructor which gets called?)

abir

You should not derive from STL container classes. Their destructors are
not virtual.
Although, in my book, composition can be a form of private inheritence.
Why not template the class? In your example, if element class Corres,
whatever that is, overloads the global op<<, you can add features as
shown below. Note that both primitive int and class std::string already
have an overloaded operator<<.

The point here is that if you are going to compose with a std::vector,
do it to add features, otherwise you would not need to wrap the
container.
How you do that is not very complicated:

a) learn how to declare and use templates
b) pass by reference
c) dependant types need the typename keyword
d) overload operators

#include <iostream>
#include <ostream>
#include <string>
#include <vector>

template< typename T >
class Vector
{
std::vector< T vt;
public:
Vector() : vt() { } // an empty vector of TsSince primitive types
like int and other classes like std::string already have an overload
for global op<<, i can iterate through the elements simply by writing:

std::cout << name_of_container;
~Vector() { }
/* member functions */
size_t size() const { return vt.size(); }
void push_back( const T& r_t ) { vt.push_back( r_t ); }
/* friend op */
friend
std::ostream&
operator<<( std::ostream& os, Vector< T >& r_v )
{ // std::vector<T>::iterator is a dependant type
typedef typename std::vector< T >::iterator VIter;
VIter iter = r_v.vt.begin();
for ( iter; iter != r_v.vt.end(); ++iter )
{
os << *iter << std::endl;
}
return os;
}
};

int main()
{
Vector< int integers;
for ( int n = 0; n < 5; ++n )
{
integers.push_back( n );
}
std::cout << integers; // op<< overload

Vector< std::string strings;
strings.push_back( "first string" );
strings.push_back( "second string" );
strings.push_back( "third string" );
strings.push_back( "fourth string" );
std::cout << strings; // op<< overload

return 0;
}

/*
0
1
2
3
4
first string
second string
third string
fourth string
*/
This is the other option which I thought (and mentioned in my first
post). Using delegate is always better, I think. It both protects
security, and makes a cleaner interface (I had mentioned like Java
Vector & Stack). And templating Vector is not usefull for my case, as I
am going to use only and only CorresVector where some additional
methods are there, to perform some additional job, and may want to
build a library from that directly for my core engine part of the
application. Not that it can not be done otherway, (like performing
the tasks after push_back operation, say some notification event
handling) but assigning the tasks in the operation itself secures code.

However unlike the code you presented, I need many features of vector
rather than just push_back. Most importantly, I need the iterator
functionality, and want to apply many stl algorithms to CorresVector
just like vector. That says I need to delegate many more functions
rather than size & push_back( say aoo of the iterator traits, const &
non const vercion of begin end etc, reserve, indexing operators, at and
others). It is not difficult, it is tedious!
And in code CorresVector is going to be used only one place, i.e inside
Session class, like,
class Session{
private:
CorresVector _corres;
};
and some reference get methods (const & non const). There is no other
place where it will be used (there is no other place there it can be
used also :) ). Thus I think it will not cause any memory leak in this
particular case(i.e not freeing the elements on destruction). Session
class has a virtual destructor, and hence it will always get destroyed
even when inheriting & storing in SessionManager (a singleton) like
FileSession, OnlineSession etc.
Can you say a yes/no about risk to this specific case?
For general case, I like your answer, and sooner or later will
implement it.
btw Corres means Correspondence (a special kind of distance structure)

Thanks for the reply & the worning.

Sep 26 '06 #7

P: n/a

Salt_Peter wrote:
toton wrote:
Hi,
I want to have a vector like class with some additional functionality
(cosmetic one). So can I inherit a vector class to add the addition
function like,

You should not derive from STL container classes. Their destructors are
not virtual.
That should read "you should not polymorphically delete objects of
types derived from STL container classes. STL container classes do not
have virtual destructors."
Although, in my book, composition can be a form of private inheritence.
Why not template the class? In your example, if element class Corres,
whatever that is, overloads the global op<<, you can add features as
shown below. Note that both primitive int and class std::string already
have an overloaded operator<<.

The point here is that if you are going to compose with a std::vector,
do it to add features, otherwise you would not need to wrap the
container.
How you do that is not very complicated:

a) learn how to declare and use templates
b) pass by reference
c) dependant types need the typename keyword
d) overload operators

#include <iostream>
#include <ostream>
#include <string>
#include <vector>

template< typename T >
class Vector
{
std::vector< T vt;
public:
Vector() : vt() { } // an empty vector of TsSince primitive types
like int and other classes like std::string already have an overload
for global op<<, i can iterate through the elements simply by writing:

std::cout << name_of_container;
~Vector() { }
/* member functions */
size_t size() const { return vt.size(); }
void push_back( const T& r_t ) { vt.push_back( r_t ); }
/* friend op */
friend
std::ostream&
operator<<( std::ostream& os, Vector< T >& r_v )
{ // std::vector<T>::iterator is a dependant type
typedef typename std::vector< T >::iterator VIter;
VIter iter = r_v.vt.begin();
for ( iter; iter != r_v.vt.end(); ++iter )
{
os << *iter << std::endl;
}
return os;
}
};
How is that class superior to this? If used with your program below it
produces the same output.

template <typename T>
class Vector : public std::vector<T>
{
friend std::ostream& operator<<(std::ostream& os, Vector< T >& r_v)
{
typedef typename std::vector< T >::iterator VIter;
VIter iter = r_v.begin();
for ( iter; iter != r_v.end(); ++iter )
{
os << *iter << std::endl;
}
return os;
}
};
int main()
{
Vector< int integers;
for ( int n = 0; n < 5; ++n )
{
integers.push_back( n );
}
std::cout << integers; // op<< overload

Vector< std::string strings;
strings.push_back( "first string" );
strings.push_back( "second string" );
strings.push_back( "third string" );
strings.push_back( "fourth string" );
std::cout << strings; // op<< overload
But your class can't do this unless you go back and change it.

strings.pop_back();
std::cout << strings;
>
return 0;
}

/*
0
1
2
3
4
first string
second string
third string
fourth string
first string
second string
third string
*/
Gavin Deane

Sep 26 '06 #8

P: n/a
Noah Roberts wrote:
toton wrote:
>Hi,
I want to have a vector like class with some additional functionality
(cosmetic one). So can I inherit a vector class to add the addition
function like,

CorresVector : public vector<Corres>{
public:
void addCorres(Corres& c); //it do little more than push_back
function.
}
Or I need to do a composition to do it (i.e storing the vector inside
Corresvector & delegating the necessary functionality). I want to know
that whether in this case (inheriting) is allowed for containers, i.e
will the container will get freed when CorresVector gets destoryed (i.e
vector has a virtual destructor which gets called?)

No, vector does not have a virtual destructor. It doesn't have any
virtual functions. You can inherit from a vector but you can't do so
polymorphically.
But that's really two different questions. Yes, when CorresVector gets
destroyed, its base will, too. No, if you have a pointer to the base and
you delete that, you have no guarantees of what will happen, because the
base type does not have a virtual destructor.

--

-- Pete

Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.
Sep 26 '06 #9

P: n/a

Gavin Deane wrote:
Salt_Peter wrote:
toton wrote:
Hi,
I want to have a vector like class with some additional functionality
(cosmetic one). So can I inherit a vector class to add the addition
function like,
You should not derive from STL container classes. Their destructors are
not virtual.

That should read "you should not polymorphically delete objects of
types derived from STL container classes. STL container classes do
not
have virtual destructors."
yes, of course. But isn't that the goal here?
Otherwise, why bother inheriting from a std::vector?
>
Although, in my book, composition can be a form of private inheritence.
Why not template the class? In your example, if element class Corres,
whatever that is, overloads the global op<<, you can add features as
shown below. Note that both primitive int and class std::string already
have an overloaded operator<<.

The point here is that if you are going to compose with a std::vector,
do it to add features, otherwise you would not need to wrap the
container.
How you do that is not very complicated:

a) learn how to declare and use templates
b) pass by reference
c) dependant types need the typename keyword
d) overload operators

#include <iostream>
#include <ostream>
#include <string>
#include <vector>

template< typename T >
class Vector
{
std::vector< T vt;
public:
Vector() : vt() { } // an empty vector of TsSince primitive types
like int and other classes like std::string already have an overload
for global op<<, i can iterate through the elements simply by writing:

std::cout << name_of_container;
~Vector() { }
/* member functions */
size_t size() const { return vt.size(); }
void push_back( const T& r_t ) { vt.push_back( r_t ); }
/* friend op */
friend
std::ostream&
operator<<( std::ostream& os, Vector< T >& r_v )
{ // std::vector<T>::iterator is a dependant type
typedef typename std::vector< T >::iterator VIter;
VIter iter = r_v.vt.begin();
for ( iter; iter != r_v.vt.end(); ++iter )
{
os << *iter << std::endl;
}
return os;
}
};

How is that class superior to this? If used with your program below it
produces the same output.
My class is not superior in any way unless there is a need to protect
the internals or if polymorphism is involved.
>
template <typename T>
class Vector : public std::vector<T>
{
If you inherit publicly, friend is no longer required, the std::vector
is directly accessible.
friend std::ostream& operator<<(std::ostream& os, Vector< T >& r_v)
{
typedef typename std::vector< T >::iterator VIter;
VIter iter = r_v.begin();
for ( iter; iter != r_v.end(); ++iter )
{
os << *iter << std::endl;
}
return os;
}
};
or

#include <iostream>
#include <ostream>
#include <string>
#include <vector>
#include <iterator>

template< typename T >
class Vector : public std::vector< T >
{
};

template< typename T >
std::ostream&
operator<<( std::ostream& os, Vector< T >& r_v )
{
std::copy( r_v.begin(),
r_v.end(),
std::ostream_iterator< T ( std::cout , "\n") );
}

Which again brings us right back to the crux of the issue. In such a
case, why bother inheriting from std::vector? What is the reason?
>
int main()
{
Vector< int integers;
for ( int n = 0; n < 5; ++n )
{
integers.push_back( n );
}
std::cout << integers; // op<< overload

Vector< std::string strings;
strings.push_back( "first string" );
strings.push_back( "second string" );
strings.push_back( "third string" );
strings.push_back( "fourth string" );
std::cout << strings; // op<< overload

But your class can't do this unless you go back and change it.

strings.pop_back();
std::cout << strings;
Thats obvious. The rest of the interface was not implemented.
>
Gavin Deane
Sep 26 '06 #10

P: n/a

Salt_Peter wrote:
Gavin Deane wrote:
Salt_Peter wrote:
toton wrote:
Hi,
I want to have a vector like class with some additional functionality
(cosmetic one). So can I inherit a vector class to add the addition
function like,
>
You should not derive from STL container classes. Their destructors are
not virtual.
That should read "you should not polymorphically delete objects of
types derived from STL container classes. STL container classes do
not
have virtual destructors."

yes, of course. But isn't that the goal here?
Otherwise, why bother inheriting from a std::vector?
I doubt polymorphism is the OP's goal, since std::vector doesn't have
any virtual member functions at all.
#include <iostream>
#include <ostream>
#include <string>
#include <vector>
#include <iterator>

template< typename T >
class Vector : public std::vector< T >
{
};

template< typename T >
std::ostream&
operator<<( std::ostream& os, Vector< T >& r_v )
{
std::copy( r_v.begin(),
r_v.end(),
std::ostream_iterator< T ( std::cout , "\n") );
}

Which again brings us right back to the crux of the issue. In such a
case, why bother inheriting from std::vector? What is the reason?
That's a design decision for the OP. Depending on the design goal,
there may be options superior to inheritance. Composition may or may
not be one of them.

The point I was making was that lack of a virtual destructor is not
sufficient reason for rejecting inheritance, and that using composition
instead is not necessarily better because you, the programmer, are
required to manually forward all those parts of the std::vector
interface that you need to be accessible to users of the containing
class, whereas inheritance gives you that forwarding for free.
But your class can't do this unless you go back and change it.
strings.pop_back();
std::cout << strings;
Thats obvious. The rest of the interface was not implemented.
The fact that it has to be implemented manually is the problem.

Gavin Deane

Sep 26 '06 #11

P: n/a

toton wrote:
Hi,
I want to have a vector like class with some additional functionality
(cosmetic one). So can I inherit a vector class to add the addition
function like,

CorresVector : public vector<Corres>{
public:
void addCorres(Corres& c); //it do little more than push_back
function.
}
You are basically wanting to "inherit for convenience" - you seem like
a sensible fellow who understands that (a) there are issues with this
approach and (b) knows what those issues are (or at least you do know
from others' replies), so I say go for it.

Sep 26 '06 #12

P: n/a
In article <11*********************@i42g2000cwa.googlegroups. com>,
ab*******@gmail.com says...
Hi,
I want to have a vector like class with some additional functionality
(cosmetic one). So can I inherit a vector class to add the addition
function like,

CorresVector : public vector<Corres>{
public:
void addCorres(Corres& c); //it do little more than push_back
function.
}
Or I need to do a composition to do it (i.e storing the vector inside
Corresvector & delegating the necessary functionality). I want to know
that whether in this case (inheriting) is allowed for containers, i.e
will the container will get freed when CorresVector gets destoryed (i.e
vector has a virtual destructor which gets called?)
std::vector doesn't have a virtual dtor (or any virtual functions for
that matter). Since the dtor isn't virtual this would lead to undefined
behavior, but it's easy to do by accident because public inheritance
allows implicit conversion to the base class.

While composition is clearly an option, you might also want to consider
private inheritance:

class CorresVector : private std::vector<Corres{
public:
using vector::begin;
using vector::end;
using vector::erase;
void add(Corres const &c) { push_back(c); }
// ...
};

Public inheritance is easy, but somewhat dangerous because you can
accidentally (implicitly) convert a pointer to your derived class into a
pointer to the base -- and destroying that leads to undefined behavior.

Composition gives safety, but writing forwarding functions adds work.
Private inheritance is more or less a halfway point, providing the
safety of composition with a little less work -- using declarations are
clearly simpler than forwarding functions, though obviously more work
than a public base class.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Sep 27 '06 #13

P: n/a
Jerry Coffin wrote:
In article <11*********************@i42g2000cwa.googlegroups. com>,
ab*******@gmail.com says...
>Hi,
I want to have a vector like class with some additional functionality
(cosmetic one). So can I inherit a vector class to add the addition
function like,

CorresVector : public vector<Corres>{
public:
void addCorres(Corres& c); //it do little more than push_back
function.
}
Or I need to do a composition to do it (i.e storing the vector inside
Corresvector & delegating the necessary functionality). I want to know
that whether in this case (inheriting) is allowed for containers, i.e
will the container will get freed when CorresVector gets destoryed (i.e
vector has a virtual destructor which gets called?)

std::vector doesn't have a virtual dtor (or any virtual functions for
that matter). Since the dtor isn't virtual this would lead to undefined
behavior
No, there's nothing undefined in destroying an object whose type is
derived from a type that does not have a virtual destructor. You ONLY
get undefined behavior if you delete such an object through a pointer to
its base type.

, but it's easy to do by accident because public inheritance
allows implicit conversion to the base class.
This has nothing to do with destruction. Converting to the base type is
slicing, and it's a potential problem regardless of whether the base
type has virtual functions.
>
Public inheritance is easy, but somewhat dangerous because you can
accidentally (implicitly) convert a pointer to your derived class into a
pointer to the base -- and destroying that leads to undefined behavior.

Composition gives safety, but writing forwarding functions adds work.
Private inheritance is more or less a halfway point, providing the
safety of composition with a little less work -- using declarations are
clearly simpler than forwarding functions, though obviously more work
than a public base class.
Okay.

--

-- Pete

Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.
Sep 27 '06 #14

P: n/a
In article <O8******************************@giganews.com>,
pe********@acm.org says...

[ ... ]
No, there's nothing undefined in destroying an object whose type is
derived from a type that does not have a virtual destructor. You ONLY
get undefined behavior if you delete such an object through a pointer to
its base type.
Well, even I can't figure out what I wrote when you pull it apart into
half-sentences, and reply to bits and pieces that were never intended to
represent a complete thought. To clarify what I was trying to say:

1) if you have code like this:

class base {}; // note lack of virtual dtor
class derived : public base {};

base *b = new derived;
// ...
delete b;

You'd get undefined behavior. and:

2) There's absolutely NOTHING you can do in 'derived' to prevent it from
being used in that fashion (or many similar ones that cause similar
problems).

What it comes down to is fairly simple: by using public derivation,
you've _promised_ that a derived can be substituted for a base under any
and all possible circumstances. The problem arises for the simple reason
that this is a lie -- under at least one circumstance (destruction) the
substitution leads to undefined behavior.

In short, even though you _can_ get away with this as long as you're
sufficiently careful about how you use it, it's a lousy idea. Public
derivation has a specific meaning. Unless you really mean it, you
shouldn't say it by using public derivation. Public derivation from a
base class without a virtual dtor asserts a falsehood.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Sep 28 '06 #15

P: n/a
Jerry Coffin wrote:
In article <O8******************************@giganews.com>,
pe********@acm.org says...

[ ... ]
>No, there's nothing undefined in destroying an object whose type is
derived from a type that does not have a virtual destructor. You ONLY
get undefined behavior if you delete such an object through a pointer to
its base type.

Well, even I can't figure out what I wrote when you pull it apart into
half-sentences, and reply to bits and pieces that were never intended to
represent a complete thought. To clarify what I was trying to say:

1) if you have code like this:

class base {}; // note lack of virtual dtor
class derived : public base {};

base *b = new derived;
// ...
delete b;

You'd get undefined behavior. and:

2) There's absolutely NOTHING you can do in 'derived' to prevent it from
being used in that fashion (or many similar ones that cause similar
problems).

What it comes down to is fairly simple: by using public derivation,
you've _promised_ that a derived can be substituted for a base under any
and all possible circumstances.
That seems false: since the language allows public derivation of classes
without virtual destructor, public inheritance obviously does not _promise_
that a derived class can be substituted for a base under _any_
circumstances. If it did, the standard would require the destructor of a
public base to be virtual. In fact, public inheritance per se does not
promise anything but the behavior guaranteed by the standard. Any claims
and connotations beyond the technical meaning of public inheritance are
part of (local) coding standards and style guides. Those might be more or
less well-founded and lay out best practices, but they do not define a
contract for public inheritance. Most importantly, such guidelines are in
my experience always closely tied to a certain domain or programing
paradigm, e.g., OO. In a given context, they can be perfectly valid.
Presented as universal truths about C++ programming, they turn into
falsehoods rather quickly.
The problem arises for the simple reason
that this is a lie -- under at least one circumstance (destruction) the
substitution leads to undefined behavior.

In short, even though you _can_ get away with this as long as you're
sufficiently careful about how you use it, it's a lousy idea. Public
derivation has a specific meaning.
(a) The only universal meaning of public inheritance is the one provided by
the standard, which does not require a virtual destructor.

(b) In certain contexts (e.g., OO) public inheritance can acquire another
meaning, e.g., the principle of substitutability that you outlines above.
Those meanings, however, are context specific.
Unless you really mean it, you
shouldn't say it by using public derivation. Public derivation from a
base class without a virtual dtor asserts a falsehood.
Nope. See for instance std::unary_function or std::iterator. Inheriting
publicly from those classes is perfectly fine and does not assert any
falsehoods. It just happens to be outside the scope of OO design and is
more closely related to generic programming. In that context, public
inheritance from base classes without virtual destructor is quite common
and nobody knowing the corresponding idioms will read public inheritance as
indicating substitutability in all contexts.
Best

Kai-Uwe Bux
Sep 28 '06 #16

P: n/a

Kai-Uwe Bux wrote:
Jerry Coffin wrote:
In article <O8******************************@giganews.com>,
pe********@acm.org says...

[ ... ]
No, there's nothing undefined in destroying an object whose type is
derived from a type that does not have a virtual destructor. You ONLY
get undefined behavior if you delete such an object through a pointer to
its base type.
Well, even I can't figure out what I wrote when you pull it apart into
half-sentences, and reply to bits and pieces that were never intended to
represent a complete thought. To clarify what I was trying to say:

1) if you have code like this:

class base {}; // note lack of virtual dtor
class derived : public base {};

base *b = new derived;
// ...
delete b;

You'd get undefined behavior. and:

2) There's absolutely NOTHING you can do in 'derived' to prevent it from
being used in that fashion (or many similar ones that cause similar
problems).

What it comes down to is fairly simple: by using public derivation,
you've _promised_ that a derived can be substituted for a base under any
and all possible circumstances.

That seems false: since the language allows public derivation of classes
without virtual destructor, public inheritance obviously does not _promise_
that a derived class can be substituted for a base under _any_
circumstances. If it did, the standard would require the destructor of a
public base to be virtual. In fact, public inheritance per se does not
promise anything but the behavior guaranteed by the standard. Any claims
and connotations beyond the technical meaning of public inheritance are
part of (local) coding standards and style guides. Those might be more or
less well-founded and lay out best practices, but they do not define a
contract for public inheritance. Most importantly, such guidelines are in
my experience always closely tied to a certain domain or programing
paradigm, e.g., OO. In a given context, they can be perfectly valid.
Presented as universal truths about C++ programming, they turn into
falsehoods rather quickly.
The problem arises for the simple reason
that this is a lie -- under at least one circumstance (destruction) the
substitution leads to undefined behavior.

In short, even though you _can_ get away with this as long as you're
sufficiently careful about how you use it, it's a lousy idea. Public
derivation has a specific meaning.

(a) The only universal meaning of public inheritance is the one provided by
the standard, which does not require a virtual destructor.

(b) In certain contexts (e.g., OO) public inheritance can acquire another
meaning, e.g., the principle of substitutability that you outlines above.
Those meanings, however, are context specific.
Unless you really mean it, you
shouldn't say it by using public derivation. Public derivation from a
base class without a virtual dtor asserts a falsehood.

Nope. See for instance std::unary_function or std::iterator. Inheriting
publicly from those classes is perfectly fine and does not assert any
falsehoods. It just happens to be outside the scope of OO design and is
more closely related to generic programming. In that context, public
inheritance from base classes without virtual destructor is quite common
and nobody knowing the corresponding idioms will read public inheritance as
indicating substitutability in all contexts.
Best

Kai-Uwe Bux
The best thing I have learned from all these topics is that in C++
nothing can be prevented from being misused, whatever security you may
impose. And absolute security is absolutely not possible. C++ can only
tell you that "it is designed for this purpose, dont use it otherways."
The whole language and STL is designed that way (one can go out of
index, iterator can go out of range, iterator dont know their state or
the container, algo cant remove value from container, auto_ptr can be
passed by value, typesafe enum's are not enough type safe, destructors
are not virtual by default, yet it doesn't specify a final keyword to
prevent inheritance, const function can return non const reference,
delete can't set the class instance as null, null is simply an int,
bool gets automatically converted to int, ctor call and function decl
has same signature, ctor can not be delegated, yet it is allowed as
syntax, pointer and array are same yet they have same meaning only on
POD, << thinks it as shift operator, and many other). I really have to
think of an example where a class can not be misused! .
So the best thing I can do in my program ( I am the OP ! ) make a
comment ,"It is designed to use in that way, don't use it other way!" .
It will be foolish to prevent all such misuses, as there is no way I
can prevent all or some of them.
(BTW I had a post in the article for one such misuse(or mistake) and
ways to prevent is,
http://groups.google.com/group/comp....cb217bb11c77c5
but Victor Bazarov hadn't agreed with me, saying "There is no free
cheese, except in a mouse trap. ". Yesterady I discovered around a
dozon such trap where "programmers" went just by mistake (not for free
chese) and got trapped. The result is simple program crash (Silently!
giving some nonhuman readable message in windows box, and leaving no
clue for the origin of the error! )
So, "enjoy programming. If something unfortunate happens (even if it
destroyes the whole world!) don't blame me. It was NOT designed for
that purpose! ".
Cheers

Sep 28 '06 #17

P: n/a
toton wrote:
[snip}
The best thing I have learned from all these topics is that in C++
nothing can be prevented from being misused, whatever security you may
impose. And absolute security is absolutely not possible. C++ can only
tell you that "it is designed for this purpose, dont use it otherways."
The whole language and STL is designed that way (one can go out of
index, iterator can go out of range, iterator dont know their state or
the container, algo cant remove value from container, auto_ptr can be
passed by value, typesafe enum's are not enough type safe, destructors
are not virtual by default, yet it doesn't specify a final keyword to
prevent inheritance, const function can return non const reference,
delete can't set the class instance as null, null is simply an int,
bool gets automatically converted to int, ctor call and function decl
has same signature, ctor can not be delegated, yet it is allowed as
syntax, pointer and array are same yet they have same meaning only on
POD, << thinks it as shift operator, and many other). I really have to
think of an example where a class can not be misused! .
So the best thing I can do in my program ( I am the OP ! ) make a
comment ,"It is designed to use in that way, don't use it other way!" .
It will be foolish to prevent all such misuses, as there is no way I
can prevent all or some of them.
[snip]

Well put. There seem to be two schools of thought: one school emphasizes the
methods of tying the client down so that it cannot go astray; the other
school emphasizes the goal of designing a useful class and accepts that
undefined behavior may result from violating the preconditions of the
specified contract. The STL is an example for the later and, in my opinion,
establishes a precedence: it is at least not totally out of line to use
that approach to class design in C++.

That said, there is almost a continuum of design choices and some are more
hazardous than others. I would not go out of my way to safeguard against
all possible misuses, but I would also not propose a design that requires
each user of the class to read all the fine print to use it for simple
tasks without running into undefined behavior.

In the end, I think, each class should come with a set of recommended idioms
for safe use; and users should know that they have to be careful once they
depart from the recommended idioms and have to read the actual contracts.
Best

Kai-Uwe Bux
Sep 28 '06 #18

P: n/a
In article <ef**********@murdoch.acc.Virginia.EDU>, jk********@gmx.net
says...

[ ... ]
That seems false: since the language allows public derivation of classes
without virtual destructor, public inheritance obviously does not _promise_
that a derived class can be substituted for a base under _any_
circumstances.
You're takin the fact that something is standardized as meaning there
must be some circumstance under which it should be done, or is
meaningful, etc?

While I'm certainly not going to get into a long discussion over it,
this strikes me as fallacious reasoning. I guess if (for example) you
insist there's a good time to use gets, you can go ahead and do that. I
hope you'll forgive me if I pass. While I'll openly admit this isn't
_as_ dangerous as gets, it's still a bad idea -- there's simply no good
reason to do it. If you're deriving for the sake of convenience, and
don't want to allow (for example) pointers/references to your derived
class to be converted implicitly to pointers/references to the base
class, you have a choice of private or protected inheritance.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Sep 28 '06 #19

P: n/a
In article <ef**********@murdoch.acc.Virginia.EDU>, jk********@gmx.net
says...

[ ... ]
Well put. There seem to be two schools of thought: one school emphasizes the
methods of tying the client down so that it cannot go astray; the other
school emphasizes the goal of designing a useful class and accepts that
undefined behavior may result from violating the preconditions of the
specified contract.
Pardon my being blunt, but this is barely short of complete nonsense.
Attempting to write your class in a way that it's reasonably safe isn't
tying the client down.

A design does not have to encourage its clients to shoot themselves in
the feet to be useful.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Sep 28 '06 #20

P: n/a
Jerry Coffin wrote:
In article <ef**********@murdoch.acc.Virginia.EDU>, jk********@gmx.net
says...

[ ... ]
>That seems false: since the language allows public derivation of classes
without virtual destructor, public inheritance obviously does not
_promise_ that a derived class can be substituted for a base under _any_
circumstances.

You're takin the fact that something is standardized as meaning there
must be some circumstance under which it should be done, or is
meaningful, etc?
No, you are misconstruing my reasonging: The reference to the standard is
just to establish that there is no basis for your claim that public
inheritance makes the kind of promise you claim it makes.

This is completely independent of whether it can be a good idea to inherit
from classes with non-virtual destructors. That this is, indeed, the case
follows from examples like generic programming with policy classes or such
niceties as std::unary_function.

However, any of that does not mean that it is a good idea to inherit for
convenience from std::vector. But your reasoning was much wider in scope
than this particular case.

While I'm certainly not going to get into a long discussion over it,
this strikes me as fallacious reasoning. I guess if (for example) you
insist there's a good time to use gets, you can go ahead and do that.
I hope the remarks above make it clear that the reasoning runs a little
different. It should be clear, that the my reasoning, understood properly,
does not apply to gets.

I hope you'll forgive me if I pass. While I'll openly admit this isn't
_as_ dangerous as gets, it's still a bad idea -- there's simply no good
reason to do it.
So what about std::iterator and std::unary_function? What about policy
classes as featured in "Modern C++ Design"? There are plenty of good
reasons to publicly inherit from classes that do not have virtual
destructors. Your warning is good advice and firmly rooted in the paradigm
of OO design but does not extend far beyond. It does not apply in other
cases (like generic programming), where such inheritance indeed can be (and
often is) a good idea.

If you're deriving for the sake of convenience, and
don't want to allow (for example) pointers/references to your derived
class to be converted implicitly to pointers/references to the base
class, you have a choice of private or protected inheritance.
Again, consider std::binary_function and the likes of it. Here, private
inheritance is not an option for the intended use. In these cases, it is
just understood that you do not use std::binary_function<>* polymorphically
(and how/why would you: there are no virtual member functions to begin
with).
Best

Kai-Uwe Bux
Sep 28 '06 #21

P: n/a
Jerry Coffin wrote:
In article <ef**********@murdoch.acc.Virginia.EDU>, jk********@gmx.net
says...

[ ... ]
>Well put. There seem to be two schools of thought: one school emphasizes
the methods of tying the client down so that it cannot go astray; the
other school emphasizes the goal of designing a useful class and accepts
that undefined behavior may result from violating the preconditions of
the specified contract.

Pardon my being blunt, but this is barely short of complete nonsense.
Attempting to write your class in a way that it's reasonably safe isn't
tying the client down.
I think, I did not say that.

In the part you snipped, I cited the STL as an example for the second kind
of design: you get undefined behavior if you violate the contract. Do you
consider std::vector inherently unsafe because of operator[], which gives
you undefined behavior when you are out of bounds? I accept std::vector as
a class that is designed "reasonably safe": within typical idioms (loops
from begin() to end(), from 0 to size()), you get the behavior you expect,
and in cases that depart from there, you should use at().

However, I understand that one could argue that undefined behavior is to be
avoided in library classes, and from that point of view, std::vector is a
failed design. That is the difference between the two schools of though
that I see.
A design does not have to encourage its clients to shoot themselves in
the feet to be useful.
I think, I did not say that, either.
Best

Kai-Uwe Bux
Sep 28 '06 #22

P: n/a
Jerry Coffin wrote:
In article <O8******************************@giganews.com>,
pe********@acm.org says...

[ ... ]
>No, there's nothing undefined in destroying an object whose type is
derived from a type that does not have a virtual destructor. You
ONLY
get undefined behavior if you delete such an object through a
pointer to its base type.

Well, even I can't figure out what I wrote when you pull it apart
into
half-sentences, and reply to bits and pieces that were never
intended
to represent a complete thought. To clarify what I was trying to
say:

1) if you have code like this:

class base {}; // note lack of virtual dtor
class derived : public base {};

base *b = new derived;
// ...
delete b;

You'd get undefined behavior.
And that's about everything you get. If the base class has no virtual
functions, what is the use of this code anyway?

If you don't delete through a pointer to base, there *is* no problem.
and:

2) There's absolutely NOTHING you can do in 'derived' to prevent it
from being used in that fashion (or many similar ones that cause
similar problems).
There is generally nothing you can do to prevent abuse of your code,
except to document the intended use. "This class is not intended to be
used polymorphically!".
Bo Persson

Sep 28 '06 #23

P: n/a
Jerry Coffin wrote:
In article <O8******************************@giganews.com>,

Well, even I can't figure out what I wrote when you pull it apart into
half-sentences, and reply to bits and pieces that were never intended to
represent a complete thought.
Yup. Quoting everything from the beginning of your message and
responding to what that part said sure is misleading. So I'll adopt your
tactic, and snip the relevant quotes. Why confuse people with facts?

--

-- Pete

Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.
Sep 28 '06 #24

P: n/a

toton wrote:
So the best thing I can do in my program ( I am the OP ! ) make a
comment ,"It is designed to use in that way, don't use it other way!" .
That's *exactly* what you do. Write the documentation. Explain how your
class is designed to be used. Test your code to be confident that, if
used that way, it works as expected. Then, anyone who uses your class
in a way not supported by your documentation and then complains that it
causes them a problem, doesn't have a leg to stand on.

Gavin Deane

Sep 28 '06 #25

This discussion thread is closed

Replies have been disabled for this discussion.