0
votes

In the main() function below, d is a base class pointer (of type A) which points to a derived class (of type B). Yet when the member function f(int) is called on this pointer, i.e. d->f(1), the compiler calls the non-virtual function in the base class A (labelled #2), i.e.

void f(int n) const { std::cout << n; }

Why? I was expecting that since there is also a virtual function in the base class A

virtual void f(int n) { std::cout << n; }

one of the two functions f(int) in the derived class B would be called. Where am I going wrong?

class A
{
public:
    A() {}

public:
    virtual void f(int n) { std::cout << n; }  // #1
    virtual ~A() { }

    void f(int n) const { std::cout << n; } // #2 this function is called when d->f(1) is executed in main()
};

class B
    : public A
{
public:
    void f(int n) { std::cout << n; }  // #3

    void f(int n) const { std::cout << n; }  // #4
};

int main()
{
    B b;
    const A* d = &b;

    d->f(1); // this calls function #2 above - why?

    std::cout << std::endl;

    return 0;
}
1
d is a const A* so operations cannot be done on d that logically change the object it points to. So d->f(1) needs to call the const version of f(), as only that function promises not to change the object pointed to by d. Remove the const versions of f() from class A, and the result will be a diagnostic from your compiler due to attempt to call a non-const` member function of a const object. The facts that b is not const or that one version of f() is virtual are irrelevant - the const qualifier when declaring d means that d cannot be used to change b. - Peter
@Peter - oh goodness... in my rush to understand the code I completely overlooked the obvious fact that d is const. Thank you for pointing this out! - Marco
I've taken the liberty of labelling all the versions of f so that they are easier to refer to. If this is acceptable, I'll update my answer as well to use those labels. - cigien
@cigien - good idea - Marco

1 Answers

3
votes

d is a pointer to a const A. This means any call to a member function will call the const-qualified overload if one exists. In your case, the const-qualified version of f in the base class (#2) is not virtual, so the fact that d is pointing to a B object doesn't matter. The base class const-qualified overload is the one that is chosen to be called.

If you make the const-qualified overload of f in the base class virtual then the const-qualified overload in the derived class (#4) will be chosen.

Similarly, if d is a pointer to a non-const A, then the non-const-qualified overload of f in the derived class (#3) will be called, since the overload in the base class (#1) is virtual.