在 C++17 之前,实现多态通常依赖于指针、虚函数或模板。随着 std::variant 的引入,我们可以在编译期确保对象只能持有预定义的几种类型,从而实现更安全、更高效的多态。下面通过一个简单的例子,演示如何使用 std::variant 来模拟多态行为。
1. 基本使用
#include <iostream>
#include <variant>
#include <string>
struct Dog {
void speak() const { std::cout << "Woof!\n"; }
};
struct Cat {
void speak() const { std::cout << "Meow!\n"; }
};
int main() {
std::variant<Dog, Cat> animal;
animal = Dog{};
std::visit([](auto&& a){ a.speak(); }, animal);
animal = Cat{};
std::visit([](auto&& a){ a.speak(); }, animal);
}
这段代码里,animal 可以持有 Dog 或 Cat。std::visit 负责根据当前活跃的类型调用对应的 speak 方法。相比虚函数,variant 在编译期就能确定可能的类型,避免了运行时的动态派发开销。
2. 更复杂的多态
当派生类之间存在层级关系时,variant 的使用会更有趣。下面演示一个带有基类 Animal 的示例:
class Animal {
public:
virtual void speak() const = 0;
virtual ~Animal() = default;
};
class Dog : public Animal {
public:
void speak() const override { std::cout << "Woof!\n"; }
};
class Cat : public Animal {
public:
void speak() const override { std::cout << "Meow!\n"; }
};
如果想让 variant 同时保存具体对象和基类指针,可以使用 `std::unique_ptr