Re: Polymorphism without virtual in C++
feel wrote:
I am sure it's an old question. But I just find a interesting design
about this: Polymorphism without virtual function in a C++ class.
I really can't see where the polymorphic part of your code is.
You *can* create some kind of polymorphism without using the keyword
'virtual', for example by using member function pointers (rather than
virtual functions), but that doesn't really make too much sense, as
putting member pointers in the class is only counter-productive and
doesn't achieve anything 'virtual' wouldn't.
3 PImpl idiom. There is only one data mumber in root class and there
is no any other data mumber in child class and virtual funtions.
So there's a pointer to dynamically allocated data in your base class.
Exactly which part of this is polymorphic?
(Personally I really can't understand what's all the fuss about the
Pimpl idiom. It only makes classes consume more memory and slower, which
can be especially counterproductive with small classes which have to be
instantiated frequently and in large amounts. The only situation where
there may be an advantage is if the class is large, it's copied around a
lot, and the Pimpl data is reference-counted or CoW'ed.)
In my solution, the destructor of root class is not virtual, but we
can use base class pointer to point derived class object.
The base class destructor can destroy the data in the base class, yes.
I still fail to see the polymorphic part.
The real problem, as presented by others, is that if you ever add
anything in a derived class that needs to be destroyed, deleting the
object through a base-class pointer will most probably not destroy the
data in the derived class.
(Technically speaking deleting through a base class pointer without a
virtual destructor is undefined behavior even if the derived class is
empty, but I suppose most compilers will do what you expect.)
class base
{
public:
~base()
{
delete[] p;
};
protected:
int *p;
base():p(new int[10])
{
};
base(int *pp) : p(pp)
{
};
};
You probably shortened the example for the sake of brevity, but a few
comments nevertheless:
- Allocating unmanaged memory in the initialization list of the
constructor is asking for trouble.
- If objects of this class are ever copied or assigned, problems will
happen.
- Deleting a pointer given to the constructor is dubious practice at
best. You can't know what it's pointing to.
class base1 : public base
{
protected:
base1()
{
};
};
I didn't quite understand what's the purpose of this class. It does
nothing 'base' wouldn't already do.
class my : public base1
{
public:
my ()
{
p = new int[10];
};
};
This is a good example of why member variables in the protected
section are as bad as in the public section. You are assigning something
to 'p' without any regard to what it might have. In this case it has
already memory allocated to it, which is leaked by your assignment.