473,789 Members | 2,781 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Polymorphism without virtual in C++

Hi,All
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.
My solution is for some special case, trust me, very special.
1 single root class tree
2 the leaf(lowest level) classes are sealed which means we should not
inherite class from them.
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.

In my solution, the destructor of root class is not virtual, but we
can use base class pointer to point derived class object.

My question is: is this design follow the C++ standard? I tested it in
VS2005. it's ok. How about GCC?I remember that this non-virtual
destructor behavor is undefine in C++ standard.

Here is a simple code example:

class base
{
public:
~base()
{
delete[] p;
};

protected:
int *p;

base():p(new int[10])
{
};

base(int *pp) : p(pp)
{
};
};

class base1 : public base
{
protected:
base1()
{
};
};

class my : public base1
{
public:
my ()
{
p = new int[10];
};
};

int _tmain(int argc, _TCHAR* argv[])
{

base1 *o = new my;

delete o;
return 0;
}
Aug 6 '08 #1
12 2542
feel wrote:
Hi,All
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.
My question is, "why?"
My solution is for some special case, trust me, very special.
1 single root class tree
2 the leaf(lowest level) classes are sealed which means we should not
inherite class from them.
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.

In my solution, the destructor of root class is not virtual, but we
can use base class pointer to point derived class object.

My question is: is this design follow the C++ standard? I tested it in
VS2005. it's ok. How about GCC?I remember that this non-virtual
destructor behavor is undefine in C++ standard.
Correct. It's undefined behaviour to delete the derived class object
through the base class pointer in the absence of a virtual destructor.
>
Here is a simple code example:

class base
{
public:
~base()
{
delete[] p;
};
Drop the semicolons after all the function bodies. They are superfluous
(although not an error).
>
protected:
int *p;

base():p(new int[10])
{
};

base(int *pp) : p(pp)
Need a comment here that 'base' takes ownership of the pointer passed to
it. Also, probably want to declare this c-tor "explicit".
{
};
};

class base1 : public base
{
protected:
base1()
{
};
};

class my : public base1
{
public:
my ()
{
p = new int[10];
Memory leak here.
};
};

int _tmain(int argc, _TCHAR* argv[])
There is no standard function '_tmain'. There is no standard type
'_TCHAR'. You must have forgotten to include the proper header[s].
Don't check your code with VC++ without turning off extensions.
{

base1 *o = new my;

delete o;
Ka-boom! Undefined behaviour.
return 0;
}
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Aug 6 '08 #2
Victor Bazarov <v.********@com Acast.netwrote in news:g7cmb5$6so $1
@news.datemas.d e:
>{

base1 *o = new my;

delete o;

Ka-boom! Undefined behaviour.
Not necessarily Ka-boom, you might get nasal demons instead.

Seriously though, the problem is that if you add any member variables to
your derived class, Base' destructor won't know how to clean them up and
will probably only return a fraction of the memory to the heap. The rest
would be left dangling... holding onto file handles, memory, mutexes... IOW
nasal demons. In this very simple case, the undefined behavior may look
like its working, but it wouldn't take much before that changed and it did
something very hard to debug because, of course, the bug would show up
elsewhere as some random behavior.

joe
Aug 6 '08 #3
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 counterproducti ve 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.
Aug 7 '08 #4
My code is a bad example ~_^. But if you can check with AcGe classes
in ObjectARX(from AutoDesk's AutoCAD sdk), you will see the same
design. The special case is:
1 for geometry class, esp for leaf classes, we donot want user to
extend it. if you want to add other kind of geometry type, please add
new class.The leaf of class tree is 'sealed' class.
2 Polymorphism in this design is the Impl pointer in root class. we
can implementation the real version class for every leaf class.
3 Except for leaf class, every class can not be initialize in the
stack.in my example code, you can not do this:
base1 b;

Why? because I donot want a big class in my header file. For geometry
classes,such as AcGeNurbCurve, there are many method we have to put
into interface. but we can split all these method into different
catalog: 3dentity, curve, spline curve. Then you will see a class
tree. There are small number methods in every node(classes in the
tree). And it's meaningfull for a geometry class library. we may do
something for all kind of curves,right? so if we use Pimpl idiom, you
can find Polymorphism.
Aug 7 '08 #5
On Aug 6, 7:40 pm, Joe Greer <jgr...@doublet ake.comwrote:
Victor Bazarov <v.Abaza...@com Acast.netwrote in news:g7cmb5$6so $1
@news.datemas.d e:
{
base1 *o = new my;
delete o;
Ka-boom! Undefined behaviour.
Not necessarily Ka-boom, you might get nasal demons instead.
Seriously though, the problem is that if you add any member
variables to your derived class, Base' destructor won't know
how to clean them up and will probably only return a fraction
of the memory to the heap.
The problem here is that it is undefined behavior, and that
anything can happen. I can't think of a reasonalble
implementation where only part of the memory is freed, but I can
certainly think of cases where it will corrupt the free space
arena, and cause the program to crash, either immediately, or
sometime later.

--
James Kanze (GABI Software) email:ja******* **@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientier ter Datenverarbeitu ng
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Aug 7 '08 #6
On Aug 7, 1:59 am, Juha Nieminen <nos...@thanks. invalidwrote:
feel wrote:
(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 counterproducti ve
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.)
It reduces coupling, sometimes enormously.
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.
The real problem is that even if he never adds anything, it is
undefined behavior.
(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.)
Most don't. (I'd expect an immediate program crash, but with
most, it will work most of the time, only crashing in specific
cases, or much later.)

[...]
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.
Why? In this case, he's doing it in the approved fashion:
passing the pointer immediately to the base class or member.
- 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.
That depends on the contract. Is boost::shared_p tr dubious
practice? It certainly deletes a pointer given to the
constructor.

--
James Kanze (GABI Software) email:ja******* **@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientier ter Datenverarbeitu ng
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Aug 7 '08 #7
On Aug 7, 3:51 am, feel <feel...@gmail. comwrote:
My code is a bad example ~_^. But if you can check with AcGe classes
in ObjectARX(from AutoDesk's AutoCAD sdk), you will see the same
design. The special case is:
1 for geometry class, esp for leaf classes, we donot want user to
extend it. if you want to add other kind of geometry type, please add
new class.The leaf of class tree is 'sealed' class.
2 Polymorphism in this design is the Impl pointer in root class. we
can implementation the real version class for every leaf class.
3 Except for leaf class, every class can not be initialize in the
stack.in my example code, you can not do this:
base1 b;
Why? because I donot want a big class in my header file. For geometry
classes,such as AcGeNurbCurve, there are many method we have to put
into interface. but we can split all these method into different
catalog: 3dentity, curve, spline curve. Then you will see a class
tree. There are small number methods in every node(classes in the
tree). And it's meaningfull for a geometry class library. we may do
something for all kind of curves,right? so if we use Pimpl idiom, you
can find Polymorphism.
This sounds more like letter-envelope than like compilation
firewall. But I'm not sure I've fully understood it. (The
letter-envelope idiom is used to make a class with value
semantics behave polymorphically .)

--
James Kanze (GABI Software) email:ja******* **@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientier ter Datenverarbeitu ng
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Aug 7 '08 #8
On Aug 7, 4:55*pm, James Kanze <james.ka...@gm ail.comwrote:
On Aug 7, 3:51 am, feel <feel...@gmail. comwrote:
My code is a bad example ~_^. But if you can check with AcGe classes
in ObjectARX(from AutoDesk's AutoCAD sdk), you will see the same
design. The special case is:
1 for geometry class, esp for leaf classes, we donot want user to
extend it. if you want to add other kind of geometry type, please add
new class.The leaf of class tree is 'sealed' class.
2 Polymorphism in this design is the Impl pointer in root class. we
can implementation the real version class for every leaf class.
3 Except for leaf class, every class can not be initialize in the
stack.in my example code, you can not do this:
base1 b;
Why? because I donot want a big class in my header file. For geometry
classes,such as AcGeNurbCurve, there are many method we have to put
into interface. but we can split all these method into different
catalog: 3dentity, curve, spline curve. Then you will see a class
tree. There are small number methods in every node(classes in the
tree). And it's meaningfull for a geometry class library. we may do
something for all kind of curves,right? so if we use Pimpl idiom, you
can find Polymorphism.

This sounds more like letter-envelope than like compilation
firewall. *But I'm not sure I've fully understood it. *(The
letter-envelope idiom is used to make a class with value
semantics behave polymorphically .)

--
James Kanze (GABI Software) * * * * * * email:james.ka. ..@gmail.com
Conseils en informatique orientée objet/
* * * * * * * * * *Beratung in objektorientier ter Datenverarbeitu ng
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Yes, it's just like that. But the difference is:we have to work on
many kind of Envelops.
In classic letter-envelop, we can hide the real data deifinition. but
if we have to work
on a class heirarchy, for example:
Entity
^
|
Curve
^
|
Line

In this case, the real data is in Line, but we have to catalog all the
line's method into Entity, curve.
Then we can work on all kind of entity or curve.In a summary, we have
two requirement:
1 data hide, different data implementation.
2 class heirarchy.

Any comments about these requirements are welcome!
Aug 7 '08 #9
feel wrote:
2 Polymorphism in this design is the Impl pointer in root class. we
can implementation the real version class for every leaf class.
Your base class actually looks simply like a (well, some kind of)
smart pointer.

Yet I still fail to see where the polymorphism is, unless your base
class smart pointer is pointing to different class type, which can be
derived and have virtual functions. If it doesn't, then it's simply a
smart pointer which points to some numeric data, and that's it.

I don't believe the definition of "polymorphi sm" is "each object can
have differing data". If that was the case, then std::string would be
polymorphic because different instances of std::string can have
differing data (eg. different string length and contents).

In fact, I think std::string is a good comparison point. What are the
relevant differences between your classes and std::string (other than
std::string doesn't expose its private data in its protected section)?
Why? because I donot want a big class in my header file.
Is it simply a question of style? You don't want all the private data
of the class to be viewable from the header file?
Aug 7 '08 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

37
2850
by: Mike Meng | last post by:
hi all, I'm a newbie Python programmer with a C++ brain inside. I have a lightweight framework in which I design a base class and expect user to extend. In other part of the framework, I heavily use the instance of this base class (or its children class). How can I ensure the instance IS-A base class instance, since Python is a fully dynamic typing language? I searched and found several different ways to do this:
3
3700
by: Patchwork | last post by:
Hi Everyone, Please take a look at the following (simple and fun) program: //////////////////////////////////////////////////////////////////////////// ///////////// // Monster Munch, example program #include <list>
6
2048
by: john sun | last post by:
Hello, I am not newbie C++ developer infact :). But till recently I would like dig up more about C++. I know those OO details. But when people talking OO they focused on the polymorphism, and think the "old code" can call "new code" is the biggest OO feature. But as we know, in C we also can use function pointer to do the same thing with almost same effort. IMHO, virtual function is just a little easier to use than function pointer. If...
4
2405
by: Leslaw Bieniasz | last post by:
Cracow, 20.09.2004 Hello, I need to implement a library containing a hierarchy of classes together with some binary operations on objects. To fix attention, let me assume that it is a hierarchy of algebraic matrices with the addition operation. Thus, I want to have a virtual base class class Matr;
4
4431
by: Leslaw Bieniasz | last post by:
Cracow, 20.10.2004 Hello, As far as I understand, the generic programming basically consists in using templates for achieving a static polymorphism of the various code fragments, and their reuse for various template parameters. I wonder if there exist techniques for achieving a dynamic polymorphism using the generic programming. Is this possible? If yes, can anyone show me simple examples in C++
7
5394
by: Samee Zahur | last post by:
Hello, The other day I was rather shocked to find that I couldn't find a good use for runtime polymorphism! Let me explain this a bit further before you get shocked. Any function that I could previously write like this: void func1(Base& obj) { //... obj.virmeth(); //Call virtual method //...
18
3864
by: Seigfried | last post by:
I have to write a paper about object oriented programming and I'm doing some reading to make sure I understand it. In a book I'm reading, however, polymorphism is defined as: "the ability of two different objects to respond to the same request message in their own unique way" I thought that it was: "the ability of same object to respond to different messages in
1
10103
weaknessforcats
by: weaknessforcats | last post by:
Introduction Polymorphism is the official term for Object-Oriented Programming (OOP). Polymorphism is implemented in C++ by virtual functions. This article uses a simple example hierarchy which you may have seen many times in one form or another. An analysis of this example produces several problems that are not obvious but which will seriously limit your ability to use hierarchies like the example in a real program. Then, the article...
17
3884
by: Bart Friederichs | last post by:
Hello, I created the following inheritance: class Parent { public: void foo(int i); }; class Child : public Parent {
0
9666
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
10410
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
10139
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9984
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
7529
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5418
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
4093
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
3701
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2909
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.