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
voidtipo, mas a função na classe derivada é deinttipo. - 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 umAnimalobjeto. Então, a função virtual emAnimalclasse é executada dentro deprint(). - Quando
print(dog1)é chamado, o ponteiro aponta para umDogobjeto. Assim, a função virtual é substituída e a função deDogé executado dentro deprint(). - Quando
print(cat1)é chamado, o ponteiro aponta para umCatobjeto. Assim, a função virtual é substituída e a função deCaté executado dentro deprint().
Linguagem C