Funções virtuais C++
Funções virtuais C++
Neste tutorial, aprenderemos sobre a função virtual C++ e seu uso com a ajuda de exemplos.
Uma função virtual é uma função membro na classe base que esperamos redefinir em classes derivadas.
Basicamente, uma função virtual é usada na classe base para garantir que a função seja substituída . Isso se aplica especialmente aos casos em que um ponteiro de classe base aponta para um objeto de uma classe derivada.
Por exemplo, considere o código abaixo:
class Base {
public:
void print() {
// code
}
};
class Derived : public Base {
public:
void print() {
// code
}
};
Mais tarde, se criarmos um ponteiro de
Base
digite para apontar para um objeto de Derived
class e chame o print()
função, ele chama o print()
função do Base
classe. Em outras palavras, a função de membro de
Base
não é substituído.
int main() {
Derived derived1;
Base* base1 = &derived1;
// calls function of Base class
base1->print();
return 0;
}
Para evitar isso, declaramos o
print()
função do Base
class como virtual usando o virtual
palavra-chave.
class Base {
public:
virtual void print() {
// code
}
};
As funções virtuais são parte integrante do polimorfismo em C++. Para saber mais, confira nosso tutorial sobre Polimorfismo C++.
Exemplo 1:função virtual C++
#include <iostream>
using namespace std;
class Base {
public:
virtual void print() {
cout << "Base Function" << endl;
}
};
class Derived : public Base {
public:
void print() {
cout << "Derived Function" << endl;
}
};
int main() {
Derived derived1;
// pointer of Base type that points to derived1
Base* base1 = &derived1;
// calls member function of Derived class
base1->print();
return 0;
}
Saída
Derived Function
Aqui, declaramos o
print()
função de Base
como virtual
. Portanto, esta função é substituída mesmo quando usamos um ponteiro de
Base
tipo que aponta para o Derived
objeto derivado1 . Identificador de substituição de C++
O C++ 11 nos deu um novo identificador
override
que é muito útil para evitar bugs ao usar funções virtuais. Esse identificador especifica as funções de membro das classes derivadas que substituem a função de membro da classe base.
Por exemplo,
class Base {
public:
virtual void print() {
// code
}
};
class Derived : public Base {
public:
void print() override {
// code
}
};
Se usarmos um protótipo de função em
Derived
class e definir essa função fora da classe, então usamos o seguinte código:
class Derived : public Base {
public:
// function prototype
void print() override;
};
// function definition
void Derived::print() {
// code
}
Uso de substituição C++
Ao usar funções virtuais, é possível cometer erros ao declarar as funções-membro das classes derivadas.
Usando o
override
identificador solicita ao compilador para exibir mensagens de erro quando esses erros são cometidos. Caso contrário, o programa simplesmente compilará, mas a função virtual não será substituída.
Alguns desses possíveis erros são:
- Funções com nomes incorretos: Por exemplo, se a função virtual na classe base for denominada
print()
, mas acidentalmente nomeamos a função de substituição na classe derivada comopint()
. - Funções com diferentes tipos de retorno: Se a função virtual for, digamos, de
void
tipo, mas a função na classe derivada é deint
tipo. - Funções com parâmetros diferentes: Se os parâmetros da função virtual e as funções nas classes derivadas não corresponderem.
- Nenhuma função virtual é declarada na classe base.
Uso de funções virtuais C++
Suponha que tenhamos uma classe base
Animal
e classes derivadas Dog
e Cat
. Suponha que cada classe tenha um membro de dados chamado type . Suponha que essas variáveis sejam inicializadas por meio de seus respectivos construtores.
class Animal {
private:
string type;
... .. ...
public:
Animal(): type("Animal") {}
... .. ...
};
class Dog : public Animal {
private:
string type;
... .. ...
public:
Animal(): type("Dog") {}
... .. ...
};
class Cat : public Animal {
private:
string type;
... .. ...
public:
Animal(): type("Cat") {}
... .. ...
};
Agora, vamos supor que nosso programa exija que criemos dois
public
funções para cada classe:getType()
para retornar o valor de tipoprint()
para imprimir o valor de tipo
Poderíamos criar essas duas funções em cada classe separadamente e substituí-las, o que será longo e tedioso.
Ou podemos fazer
getType()
virtuais no Animal
class e, em seguida, crie um print()
único e separado função que aceita um ponteiro de Animal
tipo como seu argumento. Podemos então usar essa única função para substituir a função virtual.
class Animal {
... .. ...
public:
... .. ...
virtual string getType {...}
};
... .. ...
... .. ...
void print(Animal* ani) {
cout << "Animal: " << ani->getType() << endl;
}
Isso tornará o código mais curto , limpeza , e menos repetitivo .
Exemplo 2:Demonstração de função virtual C++
// C++ program to demonstrate the use of virtual function
#include <iostream>
#include <string>
using namespace std;
class Animal {
private:
string type;
public:
// constructor to initialize type
Animal() : type("Animal") {}
// declare virtual function
virtual string getType() {
return type;
}
};
class Dog : public Animal {
private:
string type;
public:
// constructor to initialize type
Dog() : type("Dog") {}
string getType() override {
return type;
}
};
class Cat : public Animal {
private:
string type;
public:
// constructor to initialize type
Cat() : type("Cat") {}
string getType() override {
return type;
}
};
void print(Animal* ani) {
cout << "Animal: " << ani->getType() << endl;
}
int main() {
Animal* animal1 = new Animal();
Animal* dog1 = new Dog();
Animal* cat1 = new Cat();
print(animal1);
print(dog1);
print(cat1);
return 0;
}
Saída
Animal: Animal Animal: Dog Animal: Cat
Aqui, usamos a função virtual
getType()
e um Animal
ponteiro ani para evitar repetir o print()
função em cada classe.
void print(Animal* ani) {
cout << "Animal: " << ani->getType() << endl;
}
Em
main()
, criamos 3 Animal
ponteiros para criar dinamicamente objetos de Animal
, Dog
e Cat
Aulas.
// dynamically create objects using Animal pointers
Animal* animal1 = new Animal();
Animal* dog1 = new Dog();
Animal* cat1 = new Cat();
Em seguida, chamamos o
print()
função usando estes ponteiros:- Quando
print(animal1)
é chamado, o ponteiro aponta para umAnimal
objeto. Então, a função virtual emAnimal
classe é executada dentro deprint()
. - Quando
print(dog1)
é chamado, o ponteiro aponta para umDog
objeto. Assim, a função virtual é substituída e a função deDog
é executado dentro deprint()
. - Quando
print(cat1)
é chamado, o ponteiro aponta para umCat
objeto. Assim, a função virtual é substituída e a função deCat
é executado dentro deprint()
.
Linguagem C