简体   繁体   中英

c++ polymorphism, name resolution for derived class

class Base {
public:
virtual void f(float) { cout << "Base::f(float)\n"; }
};
class Derived : public Base {
public:
virtual void f(int) { cout << "Derived::f(int)\n"; }
};
int main() {
Derived *d = new Derived();
Base *b = d;
b->f(3.14F);
d->f(3.14F);
}

-C++ does not support contravaraint return type, so the f(int) does not override f(float)

-Polymorphism is supported by C++, so both d and b should point to vtable for the derived class.

-vtable for derived class is something like 0: f(float), 1: f(int) etc.

My answer for the question is Base::f(float) is called twice, but the answer is:

Base::f(float) Derived::f(int)

Why is this the case? Does accessing derived class from different pointer enforce certain rules? Far as I am aware, object slicing only occurs when using copy-ctor or copy-assignment, with pointers, they should all point to the same vtable.

Methods in different classes do not overload together; defining another f() in Derived prevents the one in Base from being considered during overload resolution.

You need to explicitly bring base definitions into derived classes when you want to add new overloads without hiding the ones defined in base classes.

public:
    using Base::f;

My take on this is that there is an implicit conversion of float to int when you call d->f(3.14F)

Your Derived class actually has 2 entries for f()

void f(int);
void f(float);

This is confirmed with g++ with the -fdump-class-hierarchy flag. We can see the output as follow :

Vtable for Base
Base::_ZTV4Base: 3u entries
0     (int (*)(...))0
4     (int (*)(...))(& _ZTI4Base)
8     (int (*)(...))Base::f

Vtable for Derived
Derived::_ZTV7Derived: 4u entries
0     (int (*)(...))0
4     (int (*)(...))(& _ZTI7Derived)
8     (int (*)(...))Base::f
12    (int (*)(...))Derived::f

Your Derived class does not touch the f function from the base class since the definitions do not match. The code compiles because there is a implicit conversion which exists between float and int.

Try the following

class Derived : public Base {
public:
virtual void f(std::string) { cout << "Derived::f(string)\n"; }
};

Then this code will not compile as Derived:f(...) will hide the Base::f(...) definition. This is often referred as inheritance shadowing.

So calling b->f(3.14F) will resolve within the Base table and d->f(3.14F) will resolve with the Derived table, which shadows Base.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM