Última atualização:2026-10-12
Polimorfismo em C++: funções virtuais, CRTP e variant¶
Teste de desempenho de polimorfismo em C++: CRTP vs std::variant vs virtual¶
Polimorfismo é um conceito importante da programação orientada a objetos: permite que uma única interface represente tipos diferentes. O C++ oferece várias formas de implementar polimorfismo; este artigo discutirá o polimorfismo em três cenários:
- Funções virtuais: a forma tradicional de implementar polimorfismo em C++ é usar funções virtuais. Isso envolve usar classe base e classes derivadas para realizar implementações específicas.
- std::variant: introduzido no C++17, o std::variant implementa um polimorfismo sem necessidade de herança.
- CRTP (Curiously Recurring Template Pattern): o CRTP é uma técnica bastante particular, que implementa polimorfismo por meio do padrão recursivo curioso de templates.
As combinações de cenários testadas foram as seguintes:
- crtp puro
- crtp + std::variant
- virtual
- std::variant + std::visit
- std::variant + std::get_if
- std::variant + std::holds_alternative
Compiladores usados:
- gcc 13.2
- clang17.0
O código completo do teste já foi colocado no Planeta; aqui colo o código-chave
class Shape {
public:
virtual ~Shape() = default;
virtual double area() const = 0;
};
class Circle : public Shape
class Rectangle : public Shape
// virtual
static void BM_VirtualFunction(benchmark::State& state) {
std::vector<std::unique_ptr<Shape>> shapes;
shapes.reserve(1000);
for (int i = 0; i < 1000; ++i) {
if (i % 2 == 0) {
shapes.emplace_back(std::make_unique<Circle>(5.0));
} else {
shapes.emplace_back(std::make_unique<Rectangle>(4.0, 6.0));
}
}
for (auto _ : state) {
double totalArea = 0.0;
for (const auto& shape : shapes) {
totalArea += shape->area();
}
benchmark::DoNotOptimize(totalArea);
}
}
BENCHMARK(BM_VirtualFunction);
static void BM_VariantVisit(benchmark::State& state) {
std::vector<std::variant<Circle, Rectangle>> shapes;
shapes.reserve(1000);
for (int i = 0; i < 1000; ++i) {
if (i % 2 == 0) {
shapes.emplace_back(Circle(5.0));
} else {
shapes.emplace_back(Rectangle(4.0, 6.0));
}
}
for (auto _ : state) {
double totalArea = 0.0;
for (const auto& s : shapes) {
totalArea += std::visit([](const auto& shape) { return shape.area(); }, s);
}
benchmark::DoNotOptimize(totalArea);
}
}
static void BM_CRTPVariant(benchmark::State& state) {
std::vector<ShapeVariant> shapes;
shapes.reserve(1000);
for (int i = 0; i < 1000; ++i) {
if (i % 2 == 0) {
shapes.emplace_back(crtp_light::Circle(5.0));
} else {
shapes.emplace_back(crtp_light::Rectangle(4.0, 6.0));
}
}
for (auto _ : state) {
double totalArea = 0.0;
for (const auto& s : shapes) {
totalArea += std::visit([](const auto& shape) { return shape.area(); }, s);
}
benchmark::DoNotOptimize(totalArea);
}
}
BENCHMARK(BM_CRTPVariant);
// ...
Resultado do teste 1: compilado com gcc, vê-se que virtual e std::variant têm desempenho pouco diferente entre si, mas diferem muito de crtp.

Resultado do teste 2: compilado com clang, a tendência geral é semelhante à da compilação com gcc; apenas crtp + std::variant apresenta regressão clara de desempenho, o que possivelmente se deve ao uso de std::visit aqui.

No livro A Tour of C++, menciona-se:
This is basically equivalent to a virtual function call, but potentially faster. As with all claims of performance, this ‘‘potentially faster’’ should be verified by measurements when performance is critical. For most uses, the difference in performance is insignificant.
Isso está basicamente de acordo com este teste.
Tópicos relacionados¶
- Teste de desempenho de SSO de string em C++ | C++那些事
- Comparação de desempenho: memcpy vs std::copy | C++那些事