Question

Here I have declared another virtual function in Derived class.

#include <iostream>

using namespace std;

class A{
    string s;
    public:
    A(const string& name) : s(name){}
     virtual void f1(){cout << "f1 of base class" << endl;};
};

class B : public A{
    string p;
    public:
    B(const string& name) : A(name){}
    virtual void f2(){cout << "virtual function of derived class" << endl;}
    void f1(){cout << "f1 of derived class";}
};

int main() {
    A* arr[] = {new A("John"),new B("Bob")};
    arr[0]->f1();
    arr[1]->f1();
    arr[1]->f2();
    return 0;
}

The function call arr[1]->f2() gives the error "‘class A’ has no member named ‘f2’".I am wondering why the _vptr points to the VTABLE of base class even when B is upcasted to A.

Also I wanted to know , is inlining virtual functions safe?

Was it helpful?

Solution

Because there is no such member. virtual functions take place from the class where they are declared first down through all derived classes. They do not get bubbled up. When the compiler looks at arr[ i ]->f2() it looks up the definition of arr for its type. arr has (static) type A. So, the compiler looks up A's definition for a suitable definition of f2 and doesn't find any. Hence the diagnostic.

virtual functions can be safely inlined. In fact, all in-class definitions are implicitly inlined by the compiler. So, your A::f1 is already inlined.

OTHER TIPS

You're trying to call f2() on an A*, and A doesn't have f2() declared.

virtual means that the method, when called through a pointer to a base class (including the class of the object itself), is resolved at runtime, based on the vptr table of the object you're calling it on. It doesn't make the method visible in base classes.

Inlining virtual functions is very safe but you won't necessarily get the performance boost you're expecting from it. Inlining means that the function code is copy-pasted by the compiler at the point of call. See The C++ Super-FAQ on inlining and why it's a pie in the sky

Inlining is a compile time concept. Virtual method calls, called on a pointer to a base class, are resolved at runtime.

I.e. the following call to a function that's virtual, can be inlined:

B myB("The B.");
b.f1(); // not virtual, might be inlined

Easy first:

Also I wanted to know , is inlining virtual functions safe?

Yes, virtual functions can be inlined, but polymorphism is guaranteed to always work.

For example:

B b;
b.f2();

can be resolved at compile time, without using the virtual table, because the compiler knows the object is of type B.

I am wondering why the _vptr points to the VTABLE of base class even when arr[1] is upcasted to B.

It doesn't. It points to the virtual table of class B, but the compiler doesn't see it. The virtual table is an implementation detail. You're calling a function on an A*, so B's methods aren't visible. In this simple example, it's easy, but how could, in general, the compiler tell that arr[1] is a pointer to a B in fact? That's the whole point of polymorphism, you abstract away the derived type.

What you can do is:

dynamic_cast<B*>(arr[1]) ? (dynamic_cast<B*>(arr[1]))->f2() : (void)0;

Think about it this way. At compile time, the compile is completely oblivious of the actual type of the object that arr[i] is pointing to. That type only becomes known at runtime. So when you write something like this:

arr[i]->f2();

the compiler doesn't know what code to produce to make that call happen. What is f2? Is it the f2 that is declared in B? What if you also have a a subclass of A called C, which also has a virtual function named f2, and the object that arr[i] points to just happens to be of type C? We don't know.

You will immediately see that the only sane behavior in such case is to produce an error.

arr[1] is of type A* which doesn't have a method called f2. You'd have to cast arr[1] to B*, but I don't think that's a good idea. Change your data structures instead.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top