多态(Polymorphism)是面向对象程序设计最重要的特性之一。C++ 通过结合虚函数和指针(引用)来实现多态。作为 C++ 用户,你当然知道如何将虚函数和指针(引用)结合起来以实现多态。但在这些概念之间,可能还存在些许模糊地细节问题。
虚函数的定义
根据 C++ 标准,虚成员函数应在类内定义声明,且必须有定义(实现)。注意,在类外定义实现虚成员函数时,不能再加 virtual 关键字。
struct Foo {
virtual void foo() { // declare and define at the same time, inside the class definition.
std::cout << "Foo::foo()" << std::endl;
}
};
struct Bar {
virtual void bar();
};
void Bar::bar() {
std::cout << "Bar::bar()" << std::endl;
}
不过,C++ 标准没有要求必须在编译期对这条规则进行诊断。也就是说,如果没有给出虚成员函数的实现,编译器可能不会报错。不过,链接器可能会提示引用了未定义的符号这样的错误。
纯虚函数的定义
纯虚函数可以有定义,并且有时我们必须给出纯虚函数的定义。不过有一点需要注意:和其它成员函数不同,纯虚函数的定义必须实现在类外定义。类外定义也是不需要加virtual关键字的。
对于纯虚函数,我们可以:
- 在类定义中声明纯虚函数,并且不给实现;
- 在类定义中声明纯虚函数,并且在类定义之外给出实现。
struct Abstract {
virtual void fun() = 0; // pure virtual
~Abstract() {
// fun(); // undefined behavior
Abstract::fun(); // OK: non-virtual call
}
};
// definition of the pure virtual function
void Abstract::fun() {
std::cout << "A::fun()\n";
}
struct Concrete : Abstract {
void f() override {
Abstract::fun(); // OK: calls pure virtual function
}
~Concrete() {
fun(); // OK: calls Concrete::fun()
}
};