面试题答案
一键面试#include <iostream>
class Animal {
public:
void makeSound() {
std::cout << "Animal makes a sound." << std::endl;
}
};
class Dog : public Animal {
public:
// 按照非虚函数规则,这里不重写基类的makeSound函数
// 如果要改变行为,可在派生类中新增函数
void bark() {
std::cout << "Dog barks." << std::endl;
}
};
class Cat : public Animal {
public:
// 同理,这里也不重写基类的makeSound函数
// 若有不同行为,新增函数
void meow() {
std::cout << "Cat meows." << std::endl;
}
};
解释
- 非虚函数规则:非虚函数在派生类中不应该被重写。因为非虚函数的行为是由对象的静态类型决定的,而不是动态类型。这意味着,无论对象的实际类型是什么,只要它的静态类型是基类类型,调用的就是基类的非虚函数。
- 设计理由:如果在派生类中重写非虚函数,会破坏这种静态绑定的特性,导致程序的行为不符合预期。例如,如果一个函数接收
Animal
类型的参数并调用makeSound
,无论传入的是Dog
还是Cat
对象,调用的都应该是Animal
类的makeSound
函数,以保证一致性。
违反规则的问题
- 行为混淆:如果在
Dog
或Cat
中重写makeSound
,当通过Animal
类型的指针或引用调用makeSound
时,可能会期望调用Animal
的makeSound
,但实际上调用的是派生类重写的版本,导致行为不可预测。 - 维护困难:破坏了继承体系中关于非虚函数的设计原则,使得代码的理解和维护变得更加困难,尤其是在大型项目中。
int main() {
Animal animal;
Dog dog;
Cat cat;
animal.makeSound();
dog.makeSound();
dog.bark();
cat.makeSound();
cat.meow();
return 0;
}
在main
函数中可以看到,通过不同类型的对象调用makeSound
函数,遵循了非虚函数的静态绑定规则。同时,通过调用派生类新增的函数展示不同的行为。