C ++: наследование и разрешение перегрузки - PullRequest
3 голосов
/ 03 февраля 2012

Я читаю головоломку C ++ здесь: http://gotw.ca/gotw/005.htm

Я не понял его объяснения статического и динамического разрешения перегрузки (или параметров по умолчанию), поэтому я попытался решить проблему и сам написать несколько тестов:

class Base {
    public:
    virtual void foo() {cout << "base/no parameters" << endl;}
    virtual void foo(int a) {cout << "base/int" << endl;}
};

class Derived : public Base {
    public:
    void foo() {cout << "derived/no parameters" << endl;}
    void foo(double a) {cout << "derived/int" << endl;}
};

int main() {
    Base* ptr = new Derived;
    ptr->foo();
    ptr->foo(1.0);
}

Вывод:

derived/no parameters
base/int

Как происходит при вызове foo(), C ++, кажется, распознает, что он указывает на Derived, но в вызове foo(1.0), C ++ не видит функцию void foo(double a) в классе Derived?

В моем представлении есть конкурирующие идеи, что C ++ имеет полиморфизм, который объясняет первый вызов, но это разрешение перегрузки выполняется во время компиляции, которое объясняет второй вызов.

Ответы [ 6 ]

3 голосов
/ 03 февраля 2012

Это классический пример для Скрытие функций .
Функция в классе Dervied переопределяет Функция Базового класса тогда и только тогда, когда:

  1. virtual ключевое слово присутствует по крайней мере в функции базового класса.
  2. Функция в производном классе имеет точно такую ​​же сигнатуру, что и функция базового класса.

Второе правило имеет исключение, где Ковариантные типы возврата разрешены.

Учитывая два приведенных выше правила:

Функция без параметра foo() в производном классе overiddes Базовый класс foo() и, следовательно, динамическая диспетчеризация работает для него, как и ожидалось.

Версия foo(double) с одним параметром не переопределяет Базовый класс foo(int) функционирует, просто Скрывает это. Поскольку отсутствует переопределение, отсутствует динамическая диспетчеризация, компилятор просто вызывает функцию foo(int), которую находит в области действия базового класса.

2 голосов
/ 03 февраля 2012

ptr относится к типу Base*

Единственная функция в Base, принимающая 1.0 в качестве параметра: virtual void foo(int a).

Теперь, помните, чтобы функция была практически переопределена, она должна идеально соответствовать сигнатуре (минус дисперсия, но она не применяется в вашем случае). Вы не переопределяете foo(int), но фактически создаете новый foo(double).

2 голосов
/ 03 февраля 2012

C ++ не видит void foo(double a) функцию в производном классе?

C ++ видит функцию, но она не связана с Base::foo s virtual ness из-за разницы в сигнатуре функции :

virtual void Base::foo(int);  // 'Base' signature
void Derived::foo(double);    // 'Derived' signature

Итак, здесь есть 2 важных факта для Derived::foo(double):

  1. не относится (переопределить) к Base::foo(int)
  2. не virtual метод (даже сделать его virtual не помогает)

1-й пункт важнее, потому что когда вы звоните

// 'ptr' refers 'Base' method signature; so 'double' implicitly converts to 'int'
ptr->foo(1.0);

Base указатель используется. В списке vtable есть только одна запись Base::foo(int). И поэтому он называется.

1 голос
/ 03 февраля 2012
class Base {
    public:
    virtual void foo() {cout << "base/no parameters" << endl;}
    virtual void foo(int a) {cout << "base/int" << endl;}
        };

class Derived : public Base {
    public:
    void foo() {cout << "derived/no parameters" << endl;}
    void foo(int a) {cout << "derived/int" << endl;}
     //  then your derived class function   will call 
};

int main() {
    Base* ptr = new Derived;
    ptr->foo();
    ptr->foo(1.0);

}
1 голос
/ 03 февраля 2012

C ++ не может видеть void foo(double a) в классе Derived, поскольку он не переопределяет виртуальную функцию с подписью void foo(double a) в классе Base (где вы пытаетесь вызвать егоfrom).

В классе Base есть void foo(int a), но это совершенно другая функция в соответствии с правилами C ++.


С другой стороны,void foo() в классе Derived переопределяет виртуальную функцию void foo() в классе Base, поскольку они обе имеют одинаковую подпись.

0 голосов
/ 03 февраля 2012

статическое и динамическое разрешение перегрузки !!!Что это значит здесь?

Перегрузка всегда статически связана, и функции должны быть определены внутри класса (ни одна функция не находится в базовом классе, а другая функция находится в производном классе).

Таким образом, foo (double a) и foo (int a) не перегружены.При этом они не переопределяются, так как подпись другая.Вот почему нет виртуального механизма для утверждения ptr-> foo (1.0);

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...