Виртуалы могут иметь значения по умолчанию. Значения по умолчанию в базовом классе не наследуются производными классами.
Какой тип по умолчанию используется, т. Е. Базовый класс или производный класс, определяется статическим типом, используемым для вызова функции. Если вы вызываете объект базового класса, указатель или ссылку, используется значение по умолчанию, обозначенное в базовом классе. И наоборот, если вы вызываете через объект производного класса, указатель или ссылку, используются значения по умолчанию, обозначенные в производном классе. Под стандартной цитатой есть пример, демонстрирующий это.
Некоторые компиляторы могут делать что-то другое, но вот что говорят стандарты C ++ 03 и C ++ 11:
8.3.6.10:
Вызов виртуальной функции (10.3) использует аргументы по умолчанию в объявлении виртуальной функции, определяемой статическим типом указателя или ссылкой, обозначающей объект. Переопределяющая функция в производном классе не получает аргументы по умолчанию от перезаписываемой функции. Пример:
struct A {
virtual void f(int a = 7);
};
struct B : public A {
void f(int a);
};
void m()
{
B* pb = new B;
A* pa = pb;
pa->f(); //OK, calls pa->B::f(7)
pb->f(); //error: wrong number of arguments for B::f()
}
Вот пример программы, чтобы продемонстрировать, какие значения по умолчанию выбраны. Я использую struct
s здесь, а не class
es просто для краткости - class
и struct
они практически одинаковы почти во всех отношениях, кроме видимости по умолчанию.
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
using std::stringstream;
using std::string;
using std::cout;
using std::endl;
struct Base { virtual string Speak(int n = 42); };
struct Der : public Base { string Speak(int n = 84); };
string Base::Speak(int n)
{
stringstream ss;
ss << "Base " << n;
return ss.str();
}
string Der::Speak(int n)
{
stringstream ss;
ss << "Der " << n;
return ss.str();
}
int main()
{
Base b1;
Der d1;
Base *pb1 = &b1, *pb2 = &d1;
Der *pd1 = &d1;
cout << pb1->Speak() << "\n" // Base 42
<< pb2->Speak() << "\n" // Der 42
<< pd1->Speak() << "\n" // Der 84
<< endl;
}
Вывод этой программы (на MSVC10 и GCC 4.4):
Base 42
Der 42
Der 84