c++中“virtual” 虚函数
必须显式使用virtual关键字需要手动管理虚函数表性能可控,但语法复杂所有方法默认就是"虚的"自动处理方法解析语法简单,但性能开销固定。
在C++中,虚函数(virtual function)是一种用于实现多态(polymorphism)的机制。它允许在基类中声明一个函数,并在派生类中重新定义(覆盖)这个函数,从而通过基类的指针或引用来调用派生类的函数。这种机制使得程序能够在运行时根据对象的实际类型来调用相应的函数,这就是所谓的动态绑定(dynamic binding)或晚期绑定(late binding)。
在C++中,虚函数的使用方式如下:
-
在基类中,使用关键字virtual声明一个函数。
-
在派生类中,可以使用override关键字(C++11及以上)来明确表示覆盖基类的虚函数。
例如:
class Base {
public:
virtual void print() {
std::cout << "Base" << std::endl;
}
};
class Derived : public Base {
public:
void print() override {
std::cout << "Derived" << std::endl;
}
};
int main() {
Base* basePtr = new Derived();
basePtr->print(); // 输出 "Derived",因为print是虚函数
delete basePtr;
return 0;
}
C++ “virtual” 虚函数与 Python 的类比
C++ 虚函数的核心概念
C++ 中的 virtual 关键字用于声明虚函数,实现运行时多态(动态绑定)。
C++ 虚函数示例
#include <iostream>
#include <vector>
using namespace std;
class Animal {
public:
// 虚函数
virtual void speak() const {
cout << "Animal sound" << endl;
}
// 纯虚函数 - 抽象方法
virtual void move() const = 0;
virtual ~Animal() = default;
};
class Dog : public Animal {
public:
void speak() const override {
cout << "Woof!" << endl;
}
void move() const override {
cout << "Dog runs on four legs" << endl;
}
};
class Bird : public Animal {
public:
void speak() const override {
cout << "Chirp!" << endl;
}
void move() const override {
cout << "Bird flies" << endl;
}
};
int main() {
vector<Animal*> animals;
animals.push_back(new Dog());
animals.push_back(new Bird());
// 运行时多态 - 通过基类指针调用派生类方法
for (auto animal : animals) {
animal->speak(); // 调用实际对象的speak方法
animal->move(); // 调用实际对象的move方法
}
// 清理
for (auto animal : animals) {
delete animal;
}
return 0;
}
输出:
Woof!
Dog runs on four legs
Chirp!
Bird flies
Python 中的等价概念
在 Python 中,所有方法本质上都是"虚的" - Python 天然支持运行时多态。
Python 等价实现
from abc import ABC, abstractmethod
from typing import List
class Animal(ABC):
@abstractmethod
def speak(self) -> None:
pass
@abstractmethod
def move(self) -> None:
pass
class Dog(Animal):
def speak(self) -> None:
print("Woof!")
def move(self) -> None:
print("Dog runs on four legs")
class Bird(Animal):
def speak(self) -> None:
print("Chirp!")
def move(self) -> None:
print("Bird flies")
def main():
animals: List[Animal] = [Dog(), Bird()]
# Python 天然的多态 - 类似 C++ 虚函数
for animal in animals:
animal.speak() # 动态调用实际对象的方法
animal.move() # 动态调用实际对象的方法
if __name__ == "__main__":
main()
详细对比
1. 基本多态行为
| 特性 | C++ | Python |
|---|---|---|
| 方法重写 | 需要 virtual + override |
直接重写 |
| 运行时绑定 | 显式使用虚函数 | 默认行为 |
| 抽象方法 | virtual ... = 0 |
@abstractmethod |
2. 方法解析时机
C++ - 需要显式声明虚函数:
class Base {
public:
void nonVirtual() { cout << "Base nonVirtual" << endl; }
virtual void isVirtual() { cout << "Base isVirtual" << endl; }
};
class Derived : public Base {
public:
void nonVirtual() { cout << "Derived nonVirtual" << endl; } // 隐藏,不是覆盖
void isVirtual() override { cout << "Derived isVirtual" << endl; } // 覆盖
};
Base* obj = new Derived();
obj->nonVirtual(); // 输出: "Base nonVirtual" (静态绑定)
obj->isVirtual(); // 输出: "Derived isVirtual" (动态绑定)
Python - 所有方法都是"虚的":
class Base:
def method(self):
print("Base method")
class Derived(Base):
def method(self):
print("Derived method")
obj: Base = Derived()
obj.method() # 输出: "Derived method" (总是动态绑定)
3. 抽象基类对比
C++ 抽象类:
// 包含纯虚函数的类是抽象类
class Shape {
public:
virtual double area() const = 0; // 纯虚函数
virtual void draw() const = 0; // 纯虚函数
virtual ~Shape() = default;
};
// 必须实现所有纯虚函数才能实例化
class Circle : public Shape {
double radius;
public:
Circle(double r) : radius(r) {}
double area() const override { return 3.14 * radius * radius; }
void draw() const override { cout << "Drawing circle" << endl; }
};
Python 抽象基类:
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self) -> float:
pass
@abstractmethod
def draw(self) -> None:
pass
class Circle(Shape):
def __init__(self, radius: float):
self.radius = radius
def area(self) -> float:
return 3.14 * self.radius ** 2
def draw(self) -> None:
print("Drawing circle")
实际场景对比
场景:图形编辑器
C++ 实现(使用虚函数):
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
class Graphic {
public:
virtual void draw() const = 0;
virtual void resize(double factor) = 0;
virtual ~Graphic() = default;
};
class Circle : public Graphic {
double x, y, radius;
public:
Circle(double x, double y, double r) : x(x), y(y), radius(r) {}
void draw() const override {
cout << "Drawing Circle at (" << x << ", " << y
<< ") with radius " << radius << endl;
}
void resize(double factor) override {
radius *= factor;
cout << "Circle resized to radius " << radius << endl;
}
};
class Rectangle : public Graphic {
double x, y, width, height;
public:
Rectangle(double x, double y, double w, double h)
: x(x), y(y), width(w), height(h) {}
void draw() const override {
cout << "Drawing Rectangle at (" << x << ", " << y
<< ") size " << width << "x" << height << endl;
}
void resize(double factor) override {
width *= factor;
height *= factor;
cout << "Rectangle resized to " << width << "x" << height << endl;
}
};
class GraphicEditor {
vector<unique_ptr<Graphic>> graphics;
public:
void addGraphic(unique_ptr<Graphic> graphic) {
graphics.push_back(move(graphic));
}
void drawAll() const {
for (const auto& graphic : graphics) {
graphic->draw(); // 多态调用
}
}
void resizeAll(double factor) {
for (const auto& graphic : graphics) {
graphic->resize(factor); // 多态调用
}
}
};
Python 等价实现:
from abc import ABC, abstractmethod
from typing import List
class Graphic(ABC):
@abstractmethod
def draw(self) -> None:
pass
@abstractmethod
def resize(self, factor: float) -> None:
pass
class Circle(Graphic):
def __init__(self, x: float, y: float, radius: float):
self.x = x
self.y = y
self.radius = radius
def draw(self) -> None:
print(f"Drawing Circle at ({self.x}, {self.y}) with radius {self.radius}")
def resize(self, factor: float) -> None:
self.radius *= factor
print(f"Circle resized to radius {self.radius}")
class Rectangle(Graphic):
def __init__(self, x: float, y: float, width: float, height: float):
self.x = x
self.y = y
self.width = width
self.height = height
def draw(self) -> None:
print(f"Drawing Rectangle at ({self.x}, {self.y}) size {self.width}x{self.height}")
def resize(self, factor: float) -> None:
self.width *= factor
self.height *= factor
print(f"Rectangle resized to {self.width}x{self.height}")
class GraphicEditor:
def __init__(self):
self.graphics: List[Graphic] = []
def add_graphic(self, graphic: Graphic) -> None:
self.graphics.append(graphic)
def draw_all(self) -> None:
for graphic in self.graphics:
graphic.draw() # 自然的动态调用
def resize_all(self, factor: float) -> None:
for graphic in self.graphics:
graphic.resize(factor) # 自然的动态调用
关键差异总结
1. 显式 vs 隐式
C++:
- 必须显式使用
virtual关键字 - 需要手动管理虚函数表
- 性能可控,但语法复杂
Python:
- 所有方法默认就是"虚的"
- 自动处理方法解析
- 语法简单,但性能开销固定
2. 性能考虑
C++:
// 非虚函数 - 直接调用,快速
obj.nonVirtualMethod();
// 虚函数 - 间接调用,有开销
obj.virtualMethod(); // 通过vtable查找
Python:
# 所有方法调用都有动态查找开销
obj.method() # 总是在运行时解析
3. 设计哲学
C++哲学: “你不用的东西不用付费”
- 默认静态绑定(快速)
- 需要时使用虚函数(灵活但稍慢)
Python哲学: “简单明确”
- 默认动态绑定(灵活)
- 所有方法调用都有运行时开销
结论
C++ 的 virtual 函数 ≈ Python 的普通方法
主要区别在于:
- C++ 需要显式声明多态行为 (
virtual) - Python 默认就是多态行为
- C++ 让你在性能和灵活性之间做选择
- Python 优先考虑灵活性和开发效率
在从 C++ 转到 Python 时,可以认为 Python 中的所有方法都像是 C++ 中的虚函数,但不需要额外的语法标记。
pure virtual function
在C++中,纯虚函数(pure virtual function)是在基类中声明但没有定义的虚函数。它的语法是在函数声明的末尾加上= 0。包含纯虚函数的类称为抽象类(abstract class),抽象类不能被实例化,只能作为接口被其他类继承。
纯虚函数的主要目的是强制派生类实现该函数,从而定义一组接口规范。
在Python中,没有直接对应的语法,但是我们可以使用abc模块(Abstract Base Classes)来达到类似的效果。在Python中,我们可以使用@abstractmethod装饰器来声明一个抽象方法,这样包含抽象方法的类就不能被实例化,除非派生类实现了所有抽象方法。
下面通过一个例子来对比C++的纯虚函数和Python的抽象方法:
C++示例:
#include <iostream>
// 抽象类
class Shape {
public:
// 纯虚函数
virtual double area() const = 0;
virtual void draw() const = 0;
};
// 派生类必须实现所有纯虚函数才能被实例化
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) {}
double area() const override {
return 3.14159 * radius * radius;
}
void draw() const override {
std::cout << "Drawing a circle" << std::endl;
}
};
int main() {
// Shape s; // 错误:不能实例化抽象类
Circle c(5.0); // 正确
std::cout << "Circle area: " << c.area() << std::endl;
c.draw();
return 0;
}
C++ “pure virtual” 纯虚函数详解
什么是纯虚函数?
纯虚函数是C++中声明但没有实现的虚函数,它使类成为抽象类(不能实例化的类)。纯虚函数强制派生类提供具体的实现。
语法
virtual 返回类型 函数名(参数列表) = 0;
C++ 纯虚函数示例
基本用法
#include <iostream>
using namespace std;
// 抽象类 - 包含纯虚函数
class Shape {
public:
// 纯虚函数 - 没有实现
virtual double area() const = 0;
// 纯虚函数
virtual void draw() const = 0;
// 普通成员函数
void printInfo() const {
cout << "Area: " << area() << endl;
}
// 虚析构函数
virtual ~Shape() = default;
};
// 具体实现类
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) {}
// 必须实现纯虚函数
double area() const override {
return 3.14159 * radius * radius;
}
void draw() const override {
cout << "Drawing a circle with radius " << radius << endl;
}
};
class Rectangle : public Shape {
private:
double width, height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
// 必须实现纯虚函数
double area() const override {
return width * height;
}
void draw() const override {
cout << "Drawing a rectangle " << width << "x" << height << endl;
}
};
int main() {
// Shape shape; // 错误!不能实例化抽象类
Circle circle(5.0);
Rectangle rect(4.0, 6.0);
circle.printInfo(); // 输出: Area: 78.5397
rect.printInfo(); // 输出: Area: 24
// 通过基类指针多态调用
Shape* shapes[] = {&circle, &rect};
for (auto shape : shapes) {
shape->draw();
}
return 0;
}
Python 中的等价概念
在 Python 中,纯虚函数等价于使用 abc 模块的抽象方法。
Python 等价实现
from abc import ABC, abstractmethod
from math import pi
class Shape(ABC): # 抽象基类
@abstractmethod
def area(self) -> float:
pass # 没有实现,相当于纯虚函数
@abstractmethod
def draw(self) -> None:
pass # 没有实现,相当于纯虚函数
def print_info(self) -> None:
print(f"Area: {self.area()}")
class Circle(Shape):
def __init__(self, radius: float):
self.radius = radius
def area(self) -> float:
return pi * self.radius ** 2
def draw(self) -> None:
print(f"Drawing a circle with radius {self.radius}")
class Rectangle(Shape):
def __init__(self, width: float, height: float):
self.width = width
self.height = height
def area(self) -> float:
return self.width * self.height
def draw(self) -> None:
print(f"Drawing a rectangle {self.width}x{self.height}")
# 使用
try:
shape = Shape() # 错误!不能实例化抽象类
except TypeError as e:
print(f"错误: {e}")
circle = Circle(5.0)
rect = Rectangle(4.0, 6.0)
circle.print_info() # 输出: Area: 78.53981633974483
rect.print_info() # 输出: Area: 24.0
# 多态调用
shapes = [circle, rect]
for shape in shapes:
shape.draw()
详细对比
1. 抽象类定义对比
C++ 纯虚函数:
class AbstractClass {
public:
virtual void pureVirtualMethod() = 0; // 纯虚函数
virtual ~AbstractClass() = default;
};
Python 抽象方法:
from abc import ABC, abstractmethod
class AbstractClass(ABC):
@abstractmethod
def pure_virtual_method(self) -> None: # 抽象方法
pass
2. 接口设计对比
C++ 接口模式:
// 使用纯虚函数定义接口
class Serializable {
public:
virtual void serialize(std::ostream& os) const = 0;
virtual void deserialize(std::istream& is) = 0;
virtual ~Serializable() = default;
};
class User : public Serializable {
private:
std::string name;
int age;
public:
void serialize(std::ostream& os) const override {
os << name << " " << age;
}
void deserialize(std::istream& is) override {
is >> name >> age;
}
};
Python 接口模式:
from abc import ABC, abstractmethod
class Serializable(ABC):
@abstractmethod
def serialize(self) -> str:
pass
@abstractmethod
def deserialize(self, data: str) -> None:
pass
class User(Serializable):
def __init__(self):
self.name = ""
self.age = 0
def serialize(self) -> str:
return f"{self.name} {self.age}"
def deserialize(self, data: str) -> None:
parts = data.split()
self.name = parts[0]
self.age = int(parts[1])
高级特性对比
1. 部分实现抽象类
C++ 允许部分纯虚函数:
class DatabaseConnector {
public:
// 纯虚函数 - 必须由派生类实现
virtual void connect() = 0;
virtual void disconnect() = 0;
// 普通虚函数 - 有默认实现,但可以重写
virtual bool isConnected() const {
return connected;
}
// 非虚函数 - 不能重写
void setTimeout(int milliseconds) {
timeout = milliseconds;
}
virtual ~DatabaseConnector() = default;
protected:
bool connected = false;
int timeout = 5000;
};
Python 的类似模式:
from abc import ABC, abstractmethod
class DatabaseConnector(ABC):
def __init__(self):
self.connected = False
self.timeout = 5000
@abstractmethod
def connect(self) -> None:
pass
@abstractmethod
def disconnect(self) -> None:
pass
def is_connected(self) -> bool: # 有默认实现
return self.connected
def set_timeout(self, milliseconds: int) -> None: # 具体方法
self.timeout = milliseconds
2. 多重继承接口
C++ 多重纯虚接口:
class Drawable {
public:
virtual void draw() const = 0;
virtual ~Drawable() = default;
};
class Clickable {
public:
virtual void onClick() = 0;
virtual ~Clickable() = default;
};
// 实现多个接口
class Button : public Drawable, public Clickable {
public:
void draw() const override {
cout << "Drawing button" << endl;
}
void onClick() override {
cout << "Button clicked" << endl;
}
};
Python 多重抽象基类:
from abc import ABC, abstractmethod
class Drawable(ABC):
@abstractmethod
def draw(self) -> None:
pass
class Clickable(ABC):
@abstractmethod
def on_click(self) -> None:
pass
class Button(Drawable, Clickable):
def draw(self) -> None:
print("Drawing button")
def on_click(self) -> None:
print("Button clicked")
实际应用场景
场景:插件系统
C++ 插件接口:
// 插件接口 - 纯虚函数定义标准
class Plugin {
public:
virtual std::string getName() const = 0;
virtual std::string getVersion() const = 0;
virtual void initialize() = 0;
virtual void execute() = 0;
virtual void cleanup() = 0;
virtual ~Plugin() = default;
};
// 具体插件实现
class CalculatorPlugin : public Plugin {
public:
std::string getName() const override {
return "Calculator";
}
std::string getVersion() const override {
return "1.0";
}
void initialize() override {
cout << "Calculator plugin initialized" << endl;
}
void execute() override {
cout << "Performing calculation..." << endl;
}
void cleanup() override {
cout << "Calculator plugin cleaned up" << endl;
}
};
Python 插件接口:
from abc import ABC, abstractmethod
class Plugin(ABC):
@abstractmethod
def get_name(self) -> str:
pass
@abstractmethod
def get_version(self) -> str:
pass
@abstractmethod
def initialize(self) -> None:
pass
@abstractmethod
def execute(self) -> None:
pass
@abstractmethod
def cleanup(self) -> None:
pass
class CalculatorPlugin(Plugin):
def get_name(self) -> str:
return "Calculator"
def get_version(self) -> str:
return "1.0"
def initialize(self) -> None:
print("Calculator plugin initialized")
def execute(self) -> None:
print("Performing calculation...")
def cleanup(self) -> None:
print("Calculator plugin cleaned up")
关键差异总结
| 特性 | C++ 纯虚函数 | Python 抽象方法 |
|---|---|---|
| 语法 | virtual func() = 0; |
@abstractmethod + pass |
| 抽象类 | 包含纯虚函数的类 | 继承 ABC + 包含 @abstractmethod |
| 实例化 | 不能实例化抽象类 | 不能实例化抽象类 |
| 强制实现 | 派生类必须实现所有纯虚函数 | 派生类必须实现所有抽象方法 |
| 错误时机 | 编译时错误 | 运行时错误(实例化时) |
重要注意事项
C++ 特有的细节
class AbstractBase {
public:
virtual void pureVirtual() = 0;
// 纯虚函数可以有实现(但很少用)
virtual void pureVirtualWithImpl() = 0;
};
// 纯虚函数的实现(不常见)
void AbstractBase::pureVirtualWithImpl() {
cout << "Default implementation" << endl;
}
class Concrete : public AbstractBase {
public:
void pureVirtual() override {
cout << "Implemented pure virtual" << endl;
}
void pureVirtualWithImpl() override {
// 可以调用基类的实现
AbstractBase::pureVirtualWithImpl();
cout << "Additional implementation" << endl;
}
};
Python 特有的灵活性
from abc import ABC, abstractmethod
class FlexibleAbstract(ABC):
@abstractmethod
def required_method(self):
pass
def optional_method(self):
print("This is optional")
# Python 允许动态检查
class ConcreteClass(FlexibleAbstract):
def required_method(self):
return "Implemented"
obj = ConcreteClass()
print(hasattr(obj, 'required_method')) # True
print(hasattr(obj, 'optional_method')) # True
总结
C++ 纯虚函数 ≈ Python 的 @abstractmethod
核心相似点:
- 都用于定义必须由子类实现的接口
- 都创建不能直接实例化的抽象类
- 都强制派生类提供具体实现
主要差异:
- 语法:C++ 使用
= 0,Python 使用装饰器 - 错误检查:C++ 在编译时,Python 在运行时
- 实现要求:C++ 更严格,Python 更灵活
纯虚函数/抽象方法是面向对象设计中接口隔离和契约编程的重要工具,在两种语言中都用于创建清晰、可维护的API契约。
(注:文档部分内容可能由 AI 生成)
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐

所有评论(0)