0

I was studying Virtual Functions and Pointers. Below code made me to think about, why does one need Virtual Function when we can type cast base class pointer the way we want?

class baseclass {
public:
    void show() {
        cout << "In Base\n";
    }
};

class derivedclass1 : public baseclass {
public:
    void show() {
        cout << "In Derived 1\n";
    }
};

class derivedclass2 : public baseclass {
public:
    void show() {
        cout << "In Derived 2\n";
    }
};

int main(void) {
    baseclass * bptr[2];
    bptr[0] = new derivedclass1;
    bptr[1] = new derivedclass2;

    ((derivedclass1*) bptr)->show();
    ((derivedclass2*) bptr)->show();

    delete bptr[0];
    delete bptr[1];

    return 0;
}

Gives same result if we use virtual in base class.

In Derived 1
In Derived 2

Am I missing something?

4
  • 2
    When using polymorphism, you don't usually know the derived type. You have some pointers to the base class and operate on those. Plus you can't cast it for calling the destructor, so the base needs to be polymorphic anyway. Commented Mar 16, 2014 at 13:04
  • The idea is that you shouldn't have to cast. You shouldn't have to worry or know anything about the actual type behind the base type pointer. Commented Mar 16, 2014 at 13:06
  • The other thing is that say the client has some pointers to the base that they got from you. Now you add a new derived class and mix in some of those. The client changes nothing about their code. Also see this entry and the next. Commented Mar 16, 2014 at 13:08
  • 1
    Do not use C-style cast ((newtype)variable) in C++, especially not with OOP objects. Use static_cast if you are sure of the type, and dynamic_cast if you are not (and study what they do before using them). And mostly, do not use casts, change the architecture so that you don't need to cast. Commented Mar 16, 2014 at 13:10

3 Answers 3

3

Your example appears to work, because there is no data, and no virtual methods, and no multiple inheritance. Try adding int value; to derivedclass1, const char *cstr; to derivedclass2, initialize these in corresponding constructors, and add printing these to corresponding show() methods.

You will see how show() will print garbage value (if you cast pointer to derivedclass1 when it is not) or crash (if you cast the pointer to derivedclass2 when class in fact is not of that type), or behave otherwise oddly.


C++ class member functions AKA methods are nothing more than functions, which take one hidden extra argument, this pointer, and they assume that it points to an object of right type. So when you have an object of type derivedclass1, but you cast a pointer to it to type derivedclass2, then what happens without virtual methods is this:

  • method of derivedclass2 gets called, because well, you explicitly said "this is a pointer to derivedclass2".
  • the method gets pointer to actual object, this. It thinks it points to actual instance of derivedclass2, which would have certain data members at certain offsets.
  • if the object actually is a derivedclass1, that memory contains something quite different. So if method thinks there is a char pointer, but in fact there isn't, then accessing the data it points to will probably access illegal address and crash.

If you instead use virtual methods, and have pointer to common base class, then when you call a method, compiler generates code to call the right method. It actually inserts code and data (using a table filled with virtual method pointers, usually called vtable, one per class, and pointer to it, one per object/instance) with which it knows to call the right method. So when ever you call a virtual method, it's not a direct call, but instead the object has extra pointer to the vtable of the real class, which tells what method should really be called for that object.


In summary, type casts are in no way an alternative to virtual methods. And, as a side note, every type cast is a place to ask "Why is this cast here? Is there some fundamental problem with this software, if it needs a cast here?". Legitimate use cases for type casts are quite rare indeed, especially with OOP objects. Also, never use C-style type casts with object pointers, use static_cast and dynamic_cast if you really need to cast.

Sign up to request clarification or add additional context in comments.

3 Comments

Yes, program is giving garbage result. But why? I thought type casting is alternate option for Virtual Function.
@Marquee777 think about a virtual function, it has an implicit first parameter of this which points to a data structure in memory that contains a pointer to the vTable and the data for that object. If you type cast it a different type then the data representation is no longer valid for that type. Thus garbage.
@Marquee777 Added some text to explain, what happens when you use invalid type cast, and what happens when you use virtual methods.
2

If you use virtual functions, your code calling the function doesn't need to know about the actual class of the object. You'd just call the function blindly and correct function would be executed. This is the basis of polymorphism.

Type-casting is always risky and can cause run-time errors in large programs.

Your code should be open for extension but closed for modifications.

Hope this helps.

Comments

1

You need virtual functions where you don't know the derived type until run-time (e.g. when it depends on user input).

In your example, you have hard-coded casts to derivedclass2 and derivedclass1. Now what would you do here?

void f(baseclass * bptr)
{
    // call the right show() function
}

Perhaps your confusion stems from the fact that you've not yet encountered a situation where virtual functions were actually useful. When you always know exactly at compile-time the concrete type you are operating on, then you don't need virtual functions at all.

Two other problems in your example code:

  1. Use of C-style cast instead of C++-style dynamic_cast (of course, you usually don't need to cast anyway when you use virtual functons for the problem they are designed to solve).
  2. Treating arrays polymorphically. See Item 3 in Scott Meyer's More Effective C++ book ("Never treat arrays polymorphically").

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.