2013-09-17 5 views
1

я проходил через эту Book и я не могу обернуть мою голову вокруг этого:Наследование и указатели базового класса

если B::f(int) скрывает A::f(), почему pa1->f(); не выдаст ошибку?

Не следует указывать, что функция f() не существует в class B? И если pa1 указывает на объект class B, то pa1->f(); должен привести к ошибке, как и b.f()!

Пожалуйста, объясните это, поскольку я не могу понять это через книгу! Спасибо заранее!

#include <iostream> 
using namespace std; 

struct A { 
    virtual void f() { cout << "Class A" << endl; } 
}; 

struct B: A { 
    void f(int) { cout << "Class B" << endl; } 
}; 

struct C: B { 
    void f() { cout << "Class C" << endl; } 
}; 

int main() { 
    B b; C c; 
    A* pa1 = &b; 
    A* pa2 = &c; 
// b.f(); 
    pa1->f(); 
    pa2->f(); 
} 

ответ

1

если B::f(int) скрывает A::f(), почему pa1->f(); не выдаст ошибку?

pa1 Поскольку указывает на A и A имеет элемент, называемый f который можно назвать как это. В этом контексте любой другой класс (включая B) не имеет значения.

Не имя скрытие означает, что функция f() не существует в классе B?

Нет. Это означает, что, в контексте B, единственная функция называется f, которые могут быть найдены с помощью неквалифицированного поиска является B::f. Он не удаляет f из любого другого контекста или не позволяет ему найти квалифицированный поиск, такой как b.A::f().

И если pa1 указывает на объект класса B то pa1->f(); должно привести к ошибке как b.f() делает!

Тип динамический является B, так что тип используется (во время выполнения), чтобы вызвать виртуальные функции. Не виртуальные функции выбираются компилятором в соответствии с типом статическим, который равен A. В общем, компилятор не знает динамический тип; все, что он знает, это то, что указатель указывает на A или какой-либо неизвестный производный класс.

2

Было бы ошибкой, если вы пытались дозвониться f() из сферы B. Но вы вызываете его через указатель на базовый класс. В этом случае поиск имени и перегрузки выполняется на основе статического типа объекта, A*. Оттуда видна f().

+0

Хорошо, спасибо! –

1

Вызов pa1-> f(); сначала маршрутизируется на объект типа A, так как pa1 является указателем на этот тип. Ключевое слово virtual переадресовало бы вызов типа B, если бы была функция, которая соответствует точной (!!) сигнатуре вызова. Так как такой функции нет в типе B, функция типа A выполняется.

Я имею в виду, что в этом случае функции не «скрывают» друг друга, потому что подпись отличается. [f (void) vs. f (int)]

EDIT: Чтобы быть более понятным. f (int) и f (void) - две совершенно разные функции. В отличие от f (void) до g (int).