MST

星途 面试题库

面试题:C++非虚函数声明与继承体系中的规则考量

设计一个继承体系,基类`Animal`有一个非虚函数`makeSound`,两个派生类`Dog`和`Cat`继承自`Animal`。在派生类中,根据非虚函数声明的规则,`makeSound`函数应该如何处理?请编写完整代码,并解释为什么这样设计,同时说明如果违反相关规则可能会导致什么问题。
32.3万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
#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;
    }
};

解释

  1. 非虚函数规则:非虚函数在派生类中不应该被重写。因为非虚函数的行为是由对象的静态类型决定的,而不是动态类型。这意味着,无论对象的实际类型是什么,只要它的静态类型是基类类型,调用的就是基类的非虚函数。
  2. 设计理由:如果在派生类中重写非虚函数,会破坏这种静态绑定的特性,导致程序的行为不符合预期。例如,如果一个函数接收Animal类型的参数并调用makeSound,无论传入的是Dog还是Cat对象,调用的都应该是Animal类的makeSound函数,以保证一致性。

违反规则的问题

  1. 行为混淆:如果在DogCat中重写makeSound,当通过Animal类型的指针或引用调用makeSound时,可能会期望调用AnimalmakeSound,但实际上调用的是派生类重写的版本,导致行为不可预测。
  2. 维护困难:破坏了继承体系中关于非虚函数的设计原则,使得代码的理解和维护变得更加困难,尤其是在大型项目中。
int main() {
    Animal animal;
    Dog dog;
    Cat cat;

    animal.makeSound();
    dog.makeSound();
    dog.bark();
    cat.makeSound();
    cat.meow();

    return 0;
}

main函数中可以看到,通过不同类型的对象调用makeSound函数,遵循了非虚函数的静态绑定规则。同时,通过调用派生类新增的函数展示不同的行为。