The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

For all the C++ gurus.  Please help.

#include <iostream>

// compile, run.
// delete the word virtual, recompile, run.
// explain the output...

using namespace std;

class A
{ public:
    int x;
    virtual int getX() { return x; } ; };

class B: public A { };

int main()
{
    B b ;
    A *pA = &b;
    (*pA).x = 4;
    cout << typeid(*pA).name() << endl;
}
Lex
Saturday, July 08, 2006
 
 
When's this assignment due?
Bill
Saturday, July 08, 2006
 
 
It prints 1B.

typeId(*pA).name prints 1B.

unless I remove the word virtual then it prints 1A.

(*pA).getxX() works either way.

It's the typeId changing based on the virtual I don't understand.
Lex
Saturday, July 08, 2006
 
 
Late binding acts like a cast. Non-virtual data doesn't effect late-binding.
namehere Send private email
Saturday, July 08, 2006
 
 
> It's the typeId changing based on the virtual I don't understand.

If the class defines (or inherits) a virtual function, then the class has its own cass-specific "vtable": objects of these classes include a pointer to their class's vtable. The vtable can include RTTI. Thus, the type of the class to which a pointer points can be determined at run-time.

Conversely if the class has no virtual functions, then the class has no "vtable": objects of these classes don't include a pointer to the class's vtable. So, the type of the class to which a pointer points can only be determined at compile-time (by looking at the type of the pointer, instead of by looking at the vtable being pointed to by the object to which the pointer is pointing).

The moral is that you should often define at least one virtual function in a class, if the class is designed to be sub-classed. If nothing else, a good candidate for being defined as virtual would be the class' destructor.

For further information, research the term "vtable" to understand what a "vtable" is.
Christopher Wells Send private email
Sunday, July 09, 2006
 
 
I answered "how", rather than "why", the language implements this behaviour.

The reason "why", I think, is that when there are no virtual functions defined in a class, then the layout of the class' objects in memory must be (for backward compatibility with C, which is one of the C++ design goals) identical to the layout of an equivalent C struct.

C structs have no RTTI, and no pointer to a vtable. So when a C++ class has no virtual functions, then when you try to use RTTI keywords on it then the best that the compiler manage is compile-time (not run-time) type information.

As an experiment, try the following:

//struct
typedef struct _A
{
  int m_value;
} A;

//equivalent class without virtual functions
class B
{
  int m_value;
  void set(int value) { m_value = value; }
};

//equivalent class with at least one virtual function
class C
{
  int m_value;
  virtual void set(int value) { m_value = value; }
};

void main()
{
  cout << sizeof(A) <<endl;
  cout << sizeof(B) <<endl;
  cout << sizeof(C) <<endl;
}

I think you'll find that A and B are the same size, and C is bigger: that's because objects of type C include a (hidden, used in the implementation of the language/compiler) pointer to C's vtable.
Christopher Wells Send private email
Sunday, July 09, 2006
 
 
Bill,

You're a jerk and a fool.  It's the middle of summer.
Lenny
Sunday, July 09, 2006
 
 
And the middle of the summer semester.
Bill
Monday, July 10, 2006
 
 
So, no disagreement about jerk...
Lenny
Monday, July 10, 2006
 
 
"It's the middle of summer."

Those in Aus or NZ might disagree.

The first W in WWW is for "World" after all...  :)

To the point of the post, I find this odd. Not having used RTTI, I would have expected using an RTTI keyword would be a sufficient indicator to abandon C compatibility and hence force a vtable. I guess I would have been wrong!

I'll  have to keep this in mind...
sgf
Tuesday, July 11, 2006
 
 
also affects other RTTI functions.

for instance, add:
class C: public A { int z; int getZ(){ return z;};  };

and change the program to something like

    B b ;
    A *pA = &b;
    C c ;
    A *pA2 = &c;
    (*pA).x = 4;
    cout << typeid(*pA).name() << endl;
    cout << typeid(*pA2).name() << endl;
    class C: public A { int z; int getZ(){ return z;};  };
    C *pC = dynamic_cast<C*>(pA2);
    cout << typeid(*pC).name() << endl;

now, if you remove virtual dynamic cast throws a compiler error.

it's all in the virtual

Tuesday, July 11, 2006
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz