Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Can abstract base class have V-table?, Will the pointer to virtual destructor be entered into the virtual table?

Reply
Thread Tools

Can abstract base class have V-table?, Will the pointer to virtual destructor be entered into the virtual table?

 
 
Tomás
Guest
Posts: n/a
 
      04-06-2006

Okay, well I've a lot of free time today.


First of all, look at the following code:


#include <some_header_that_defines_geometrical_shapes>


#include <iostream>
using std::cout; using std::endl; using std::cin;

void PrintObjectInfo( ThreeDimensionalObject& object )
{
cout << object.GetClassification() << "\n\nMass: " << object.GetMass()
<<
"\n\nSurface Area: " << object.GetSurfaceArea() << "\n\n";
}


int main()
{
Sphere sphere; sphere.radius = 5;

Cylinder cylinder; cylinder.height = 2; cylinder.radius = 7;


PrintObjectInfo( sphere );
PrintObjectInfo( cylinder );
}


The idea in the code above is that the member functions,
"GetClassification", "GetMass" and "GetSurfaceArea" should be virtual so
that the function "PrintObjectInfo" can call the appropriate functions.

I've written a self-sufficient source code file to demonstrate (please keep
reading as it gets interesting):

//normal.cpp

class ThreeDimensionalObject
{
public:
virtual const char* GetClassification() const = 0;
virtual unsigned long GetMass() const = 0;
virtual unsigned long GetSurfaceArea() const = 0;
};

class Sphere : public ThreeDimensionalObject
{
public:
unsigned long radius;

virtual const char* GetClassification() const { return "Sphere"; }

virtual unsigned long GetMass() const
{
return (radius * radius * radius) * 3 / 3;
}

virtual unsigned long GetSurfaceArea() const
{
return radius * radius * 3;
}
};

class Cylinder : public ThreeDimensionalObject
{
public:
unsigned long radius;
unsigned long height;

virtual const char* GetClassification() const { return "Cylinder"; }

virtual unsigned long GetMass() const
{
return radius * height;
}

virtual unsigned long GetSurfaceArea() const
{
return height * 2 / radius;
}
};

#include <iostream>
using std::cout; using std::endl; using std::cin;

void PrintObjectInfo( ThreeDimensionalObject& object )
{
cout << object.GetClassification() << "\n\nMass: " << object.GetMass()
<<
"\n\nSurface Area: " << object.GetSurfaceArea() << "\n\n";
}


int main()
{
Sphere sphere; sphere.radius = 5;

Cylinder cylinder; cylinder.height = 2; cylinder.radius = 7;


PrintObjectInfo( sphere );
PrintObjectInfo( cylinder );
}


So then I thought, how would I achieve this if C++ didn't have virtual
functions? I'd have to implement the whole V-table concept by myself.

Step 1: I'm going to have to change the original code slightly:


#include <some_header_that_defines_geometrical_shapes>

#include <iostream>
using std::cout; using std::endl; using std::cin;

void PrintObjectInfo( ThreeDimensionalObject& object )
{
cout << object.vtable->GetClassification(&object) << "\n\nMass: " <<
object.vtable->GetMass(&object) <<
"\n\nSurface Area: " << object.vtable->GetSurfaceArea(&object) <<
"\n\n";
}


int main()
{
Sphere sphere; sphere.radius = 5;

Cylinder cylinder; cylinder.height = 2; cylinder.radius = 7;


PrintObjectInfo( sphere );
PrintObjectInfo( cylinder );
}


Here comes the code I spent the last half hour writing... enjoy!

//weird.cpp


struct VTable {};

// Forward Declarations
struct ThreeDimensionalObject;
struct Sphere;
struct Cylinder;

struct VTable_ThreeDimensionalObject : public VTable {
//Pointers to functions

const char* (*GetClassification)(const ThreeDimensionalObject*);
unsigned long (*GetMass)(const ThreeDimensionalObject*);
unsigned long (*GetSurfaceArea)(const ThreeDimensionalObject*);

VTable_ThreeDimensionalObject(
const char* (*In_GetClassification)(const ThreeDimensionalObject*),
unsigned long (*In_GetMass)(const ThreeDimensionalObject*),
unsigned long (*In_GetSurfaceArea)(const ThreeDimensionalObject*) )
: GetClassification(In_GetClassification), GetMass(In_GetMass),
GetSurfaceArea(In_GetSurfaceArea) {}

};

struct VTable_Sphere : public VTable_ThreeDimensionalObject {

//Nothing extra to add in here

VTable_Sphere(
const char* (*In_GetClassification)(const ThreeDimensionalObject*),
unsigned long (*In_GetMass)(const ThreeDimensionalObject*),
unsigned long (*In_GetSurfaceArea)(const ThreeDimensionalObject*) )
: VTable_ThreeDimensionalObject
(In_GetClassification,In_GetMass,In_GetSurfaceArea ) {}

};

struct VTable_Cylinder : public VTable_ThreeDimensionalObject {

//Nothing extra to add in here

VTable_Cylinder(
const char* (*In_GetClassification)(const ThreeDimensionalObject*),
unsigned long (*In_GetMass)(const ThreeDimensionalObject*),
unsigned long (*In_GetSurfaceArea)(const ThreeDimensionalObject*) )
: VTable_ThreeDimensionalObject
(In_GetClassification,In_GetMass,In_GetSurfaceArea ) {}
};


//Forward declarations:
extern VTable_ThreeDimensionalObject vtable_threedimensionalobject;
extern VTable_Sphere vtable_sphere;
extern VTable_Cylinder vtable_cylinder;


//Now define the classes:

struct ThreeDimensionalObject {

VTable_ThreeDimensionalObject* vtable;

ThreeDimensionalObject() : vtable( &vtable_threedimensionalobject ) {}

protected:

ThreeDimensionalObject( VTable_ThreeDimensionalObject* p ) : vtable(p)
{}
};

struct Sphere : public ThreeDimensionalObject {

Sphere() : ThreeDimensionalObject( &vtable_sphere ) {}

unsigned long radius;
};


struct Cylinder: public ThreeDimensionalObject {

Cylinder() : ThreeDimensionalObject( &vtable_cylinder ) {}

unsigned long radius;
unsigned long height;
};


//Define the actual functions

const char* GetClassification_Sphere( const ThreeDimensionalObject* ) {
return "Sphere"; }

unsigned long GetMass_Sphere( const ThreeDimensionalObject* p )
{
Sphere const &sphere = *static_cast<const Sphere*>(p);

return (sphere.radius * sphere.radius * sphere.radius) * 3 / 3;
}

unsigned long GetSurfaceArea_Sphere( const ThreeDimensionalObject* p )
{
Sphere const &sphere = *static_cast<const Sphere*>(p);

return sphere.radius * sphere.radius * 3;
}

const char* GetClassification_Cylinder( const ThreeDimensionalObject* ) {
return "Cylinder"; }

unsigned long GetMass_Cylinder(const ThreeDimensionalObject* p)
{
Cylinder const &cylinder = *static_cast<const Cylinder*>(p);

return cylinder.radius * cylinder.height;
}

unsigned long GetSurfaceArea_Cylinder(const ThreeDimensionalObject* p)
{
Cylinder const &cylinder = *static_cast<const Cylinder*>(p);

return cylinder.height * 2 / cylinder.radius;
}


//Define the vtable objects:

VTable_ThreeDimensionalObject vtable_threedimensionalobject(0, 0, 0);

VTable_Sphere vtable_sphere( GetClassification_Sphere, GetMass_Sphere,
GetSurfaceArea_Sphere );

VTable_Cylinder vtable_cylinder( GetClassification_Cylinder,
GetMass_Cylinder, GetSurfaceArea_Cylinder );


#include <iostream>
using std::cout; using std::endl; using std::cin;

void PrintObjectInfo( ThreeDimensionalObject& object )
{
cout << object.vtable->GetClassification(&object) << "\n\nMass: " <<
object.vtable->GetMass(&object) <<
"\n\nSurface Area: " << object.vtable->GetSurfaceArea(&object) <<
"\n\n";
}


int main()
{
Sphere sphere; sphere.radius = 5;

Cylinder cylinder; cylinder.height = 2; cylinder.radius = 7;


PrintObjectInfo( sphere );
PrintObjectInfo( cylinder );
}


Okay so I've alleviated by boredom for about an hour. What next?


-Tomás


 
Reply With Quote
 
 
 
 
Marcus Kwok
Guest
Posts: n/a
 
      04-06-2006
"Tom?s" <(E-Mail Removed)> wrote:
> So then I thought, how would I achieve this if C++ didn't have virtual
> functions? I'd have to implement the whole V-table concept by myself.

[snip manual implementation of vtables]

In a similar vein, have you seen Alf P. Steinbach's "Pointers" document?
(Specifically the section on Polymorphism):
http://home.no.net/dubjai/win32cpptu...ters/ch_01.pdf

(You obviously understand what you're doing, but this is for those
following along at home who might not quite follow what you did.)

--
Marcus Kwok
 
Reply With Quote
 
 
 
 
marcwentink@hotmail.com
Guest
Posts: n/a
 
      04-07-2006
> There certainly is a class. You might think that since CTemp cannot be
> instantiated by itself, there is no need for a vtable.


But that was a wrong assumption from my side. Thanks for the lesson!
It gave me more understanding of the VT concept.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Explicit destructor calls from inside base class destructor frs C++ 20 09-21-2005 09:22 AM
Deriving abstract class from non-abstract class Matthias Kaeppler Java 1 05-22-2005 01:28 PM
Format of compiler generated derived destructor when base has 'virtual ~base() throw():" qazmlp C++ 1 04-10-2005 03:09 PM
Date entered from textbox becomes null (1/1/1900) when entered into SQL table. TN Bella ASP .Net 1 07-01-2004 02:53 PM
Virtual destructor for virtual base class? Chunhui Han C++ 2 06-24-2004 10:13 AM



Advertisments