1. 问题现象与直观理解
让我们从一个实际案例开始理解这个条款的重要性。假设我们正在开发一个图形编辑器,基类Shape定义了一个绘制方法draw():
cpp复制class Shape {
public:
void draw() const {
std::cout << "Drawing a generic shape" << std::endl;
}
};
class Circle : public Shape {
public:
void draw() const { // 重新定义non-virtual函数
std::cout << "Drawing a circle" << std::endl;
}
};
当我们在代码中使用这些类时,会出现令人困惑的行为:
cpp复制Circle circle;
Shape* shapePtr = &circle;
Circle* circlePtr = &circle;
shapePtr->draw(); // 输出: Drawing a generic shape
circlePtr->draw(); // 输出: Drawing a circle
关键发现:同一个对象(circle)通过不同类型的指针调用相同方法时,产生了不同的行为。这种现象违背了面向对象编程的直觉,也是许多bug的根源。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 静态绑定的技术本质
2.1 编译时的函数决议
在C++中,non-virtual函数采用的是静态绑定(static binding),这意味着:
- 函数调用在编译时就已经确定
- 决议依据是指针或引用的静态类型(声明类型)
- 完全忽略运行时对象的实际类型
cpp复制// 编译器看到的代码
shapePtr->draw(); // 静态类型是Shape*,所以调用Shape::draw()
circlePtr->draw(); // 静态类型是Circle*,所以调用Circle::draw()
2.2 与virtual函数的对比
cpp复制class Shape {
public:
virtual void draw() const
