As diferenças entre funções virtuais e virtuais puras em C++
Este artigo descreverá as diferenças entre funções virtuais e virtuais puras em C++.
Funções virtuais e suas características em C++
As funções virtuais estão intimamente associadas ao conceito de polimorfismo. Em C++, podemos organizar diferentes classes em uma hierarquia vinculada, onde podem estar compartilhando alguns membros de dados e tendo as mesmas funções de membro expostas como a interface.
Geralmente, as classes que herdam alguma parte do código de outras classes são chamadas de classes derivadas, enquanto as que são herdadas são as classes básicas. Observe que às vezes esses termos podem ser usados alternadamente com nomes pai-filho ou superclasse-subclasse. As funções que podem ser substituídas em classes derivadas são chamadas de funções virtuais e são declaradas com a palavra-chave virtual
. As funções virtuais têm o mesmo nome dentro da hierarquia de classes fornecida e cada classe derivada pode implementar sua própria definição da função.
Se a função não for substituída, o objeto da classe derivada invoca a função definida na classe base. O programa de exemplo a seguir abaixo demonstra o uso básico de funções virtuais, definindo a função print
nas classes Engenheiro
e Funcionário
. Então podemos implementar alguma função arbitrária Func
que aceita a referência a Employee
e chama a função print
dentro do corpo.
Agora, a implementação Func
pode mudar várias vezes, mas sempre chamará a função print
correspondente com base no objeto que está sendo passado como o parâmetro. Podemos adicionar várias classes derivadas na hierarquia de classes Employee
. Cada um deles pode / não pode implementar a função print
, mas a função Func
aceitará suas instâncias e chamará a função virtual correta.
#include <iostream>
#include <string>
using std::cin;
using std::cout;
using std::endl;
using std::string;
class Employee {
public:
Employee(string fn, string ln)
: first_name(std::move(fn)), last_name(std::move(ln)) {}
virtual void print() {
cout << "name: " << first_name << "\n"
<< "last name: " << last_name << "\n";
};
protected:
string first_name, last_name;
};
class Engineer : public Employee {
public:
Engineer(string fn, string ln, string sp)
: Employee(std::move(fn), std::move(ln)), specialization(std::move(sp)) {}
void print() override {
Employee::print();
cout << "specialization: " << specialization << "\n";
}
private:
string specialization;
};
void Func(Employee &em) { em.print(); }
int main() {
Employee em1("Jim", "Jiao");
Engineer eng1("Jin", "Baker", "Aerospace Engineering");
Func(em1);
cout << "\n";
Func(eng1);
return EXIT_SUCCESS;
}
Resultado:
name : Jim last name : Jiao
name : Jin last name : Baker specialization
: Aerospace Engineering
Funções virtuais puras e tipos abstratos em C++
Por outro lado, temos o conceito de funções virtuais puras, que são declaradas semelhantes às funções virtuais regulares e incluem a notação = 0;
no final da declaração. Essas funções essencialmente não têm uma definição na classe base, onde são declaradas primeiro. Portanto, eles provavelmente serão definidos nas classes derivadas.
As classes que contêm funções virtuais puras são chamadas de classes abstratas e geralmente são utilizadas para especificar a interface das classes derivadas. Observe que as classes abstratas não podem ser instanciadas diretamente.
O próximo trecho de código implementa as classes Triangle
e Rectangle
com a classe base abstrata Shape
. Neste caso, definimos a função virtual pura printArea
em ambas as classes derivadas. Às vezes, uma classe derivada pode não definir uma função virtual pura herdada, tornando-a outra classe abstrata na hierarquia de classes fornecida. Uma classe derivada pode herdar várias funções virtuais puras. Se não definir nem mesmo um deles, a classificação abstrata é aplicada à classe.
#include <iostream>
#include <string>
#include <vector>
using std::cout;
using std::endl;
using std::string;
using std::vector;
class Shape {
public:
virtual void printArea() = 0;
};
class Triangle : public Shape {
public:
Triangle(double b, double h) : base(b), height(h) {}
void printArea() override { cout << (base * height) / 2.0; }
private:
double base;
double height;
};
class Rectangle : public Shape {
public:
Rectangle(double i1, double i2) : edges({i1, i2}) {}
void printArea() override { cout << edges[0] * edges[1]; }
private:
vector<double> edges;
};
int main() {
Triangle t1(3, 5);
t1.printArea();
cout << "\n";
Rectangle r1(3, 5);
r1.printArea();
cout << "\n";
return EXIT_SUCCESS;
}
Resultado:
7.5 15
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook