非虚函数特点
- 静态绑定:在编译期确定调用哪个函数版本。即根据对象的静态类型(声明时的类型)来决定调用的函数,而非运行时对象的实际类型。
- 不可重写:派生类不能提供与基类非虚函数同名同参数列表的不同实现,否则会被视为隐藏基类函数(不是重写)。
适合场景
- 实现基本的、稳定的功能:例如,一个
Date
类用于处理日期相关操作,其getYear
函数返回日期中的年份,这个功能通常是固定的,不会因派生类的不同而改变,适合定义为非虚函数。
class Date {
public:
int getYear() {
return year;
}
private:
int year;
};
- 强制派生类遵循特定行为:当希望所有派生类都以统一方式执行某个操作时,使用非虚函数。比如一个
Shape
类有一个drawOnConsole
函数,用于在控制台简单绘制形状轮廓,所有派生的具体形状类(如Circle
、Rectangle
)都按此统一方式绘制,就可将drawOnConsole
定义为非虚函数。
class Shape {
public:
void drawOnConsole() {
std::cout << "Drawing a shape outline on console" << std::endl;
}
};
class Circle : public Shape {};
潜在问题
- 缺乏多态灵活性:如果需要根据对象实际类型执行不同行为,非虚函数无法满足。例如在图形绘制场景中,如果希望根据不同形状(
Circle
、Rectangle
)执行不同绘制逻辑,使用非虚函数就无法实现运行时多态。
class Shape {
public:
void draw() {
std::cout << "Drawing a shape" << std::endl;
}
};
class Circle : public Shape {
public:
void draw() {
std::cout << "Drawing a circle" << std::endl;
}
};
Shape* shapePtr = new Circle();
shapePtr->draw(); // 输出 "Drawing a shape",而非 "Drawing a circle",没有体现多态
- 代码可维护性和扩展性受限:当派生类需要有不同行为但函数被定义为非虚时,修改代码可能比较麻烦,可能需要修改基类代码结构,违反开闭原则。