2015-12-10 2 views
1

Допустим, у меня есть класс A, B и CВиртуальные функции и параметры по умолчанию

class A{ 
    public: 
     virtual void f4(){ 
      cerr<<"A::f4()"<<endl; 
     } 
}; 


class B: public A{ 
    public: 
     virtual void f4(int n){ 
      cerr<<"B::f4("<<n<<")"<<endl; 
     } 
}; 

class C: public B{ 
    public: 
     virtual void f4(int n = 1){ 
      cerr<<"C::f4("<<n<<")"<<endl; 
     } 
}; 

Если у меня есть:

C c; 
A& rac = c; 
rac.f4(); 

Я ожидал, что версия Cи для f4, чтобы назвать, но это не что происходит. Может кто-нибудь объяснить?

+0

Вы имели в виду еще один '}' после строки 'cerr <<" B :: f4 "' ...? –

+0

Да, отредактировал сообщение – js091514

ответ

2

Компиляция with clang -Wall следующие предупреждения происходят:

main.cpp:14:22: warning: 'B::f4' hides overloaded virtual function [-Woverloaded-virtual] 
    virtual void f4(int n){ 
       ^
main.cpp:6:22: note: hidden overloaded virtual function 'A::f4' declared here: different number of parameters (0 vs 1) 
    virtual void f4(){ 
       ^

Эти предупреждения объяснить, что происходит. Виртуальная функция только переопределяется другой функцией с той же сигнатурой.

B::f4(int) не переопределяет A::f4(), потому что у них разные списки параметров. Вместо этого это другая виртуальная функция.

So rac.f4() просто вызывает A::f4(), который не переопределяется.

Поскольку C++ 11 вы можете помочь обнаружить эту проблему:

virtual void f4(int n) override { 
//      ^^^^^^^^ 

Тогда компилятор выдаст ошибку, если эта функция фактически не переопределяет что-то из базы.

2

Поскольку подписи f4 не совпадают между классами A и B/C.

Это сигнатура функции A для f4:

void A::f4() // no parameters 

B и использование C эта функция подписи

void B::f4(int n) 

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

FWIW, C::f4 отменяет B::f4. Указанный по умолчанию параметр class C не влияет на поведение переопределения виртуальных методов. И это точная причина, почему в моей команде мы запрещаем перегружать методы различными сигнатурами и запрещать параметры по умолчанию. Потому что это приводит к таким ошибкам.

Вот C в v-таблицы (методы, доступные на нем):

void C::f4(); // no parameters, overrides A::f4() 
void C::f4(int n); // overrides B::f4() 
+0

Поскольку C наследует от B, он должен использовать эту форму? – js091514

+0

C имеет два метода с именем f4. Тот, который наследуется от A (через B) с именем 'void f4()' и другой, который наследуется от B с именем 'void f4 (int)' – selbie

+0

Если вы внедрили 'void C :: f4 (int x)' без значения параметров по умолчанию, вы бы переопределили реализацию A. Но поскольку у вас это есть, вы переопределяете реализацию B * * другого имени метода *. – selbie