Une classe avec une (ou plusieurs) fonctions pures virtuelles virtuelles est abstraite et ne peut pas être utilisée pour créer un nouvel objet. Elle n'a donc pas de constructeur.
Je lis un livre qui fournit l'exemple suivant:
class Employee {
public:
Employee(const char*, const char*);
~Employee();
const char* getFirstName() const;
const char* getLastName() const;
virtual double earnings() const=0 // pure virtual => abstract class
virtual void print() const
private:
char* firstName, lastName;
};
Si la classe est abstraite, pourquoi avons-nous un constructeur? Il utilisera cette classe plus tard (Boss
est un public dérivé de Employee
):
void Boss::Boss (const char* first, const char* last, double s)
: Employee (first, last)
Vous avez raison de dire qu'une classe qui a une fonction virtuelle pure est abstraite et ne peut pas être instanciée. Mais vous avez tort quand vous dites qu'il ne peut pas y avoir de constructeur.
En effet, comme le montre l'exemple de votre exemple, une classe abstraite peut avoir des membres privés pouvant être utilisés par les fonctions membres de cette classe. Et ces membres doivent être initialisés. Un constructeur est un moyen de le faire (par exemple avec une liste d’initialisation dans la classe dérivée, comme le montre votre deuxième exemple), mieux à mon avis qu’une fonction init()
par exemple.
Édition de mon commentaire dans la réponse: Une classe abstraite peut avoir des variables membres et des fonctions membres potentiellement non virtuelles, de sorte que chaque classe dérivée de la première implémente des fonctionnalités spécifiques.
Ensuite, la responsabilité de l'initialisation de ces variables membres peut appartenir à la classe abstraite ( au moins toujours pour les membres privés , car la classe dérivée ne être capable de les initialiser, mais pourrait utiliser certaines fonctions membres héritées pouvant utiliser/compter sur ces membres). Ainsi, il est parfaitement raisonnable que les classes abstraites implémentent des constructeurs.
Une classe avec une fonction virtuelle pure ne peut pas être instanciée. On s'attend à ce qu'il ait des sous-classes qui l'étendront et fourniront la fonctionnalité manquante.
Ces sous-classes construiront la classe de base quand elles seront instanciées, elles appelleront le constructeur de leur super classe, raison pour laquelle les classes abstraites ont des constructeurs en c ++.
Vous ne pouvez donc pas créer directement d'instance et appeler directement le constructeur, mais les futures sous-classes le feront.
La classe Employee
a des données et ces données doivent être initialisées d'une manière ou d'une autre. Constructeur est un bon moyen de le faire.
Si la classe abstraite de base n'a pas de constructeur, comment affecteriez-vous des valeurs aux membres firstname , lastname
Pour toute classe dérivée, lorsque vous créez un objet de la classe dérivée?
Supposons qu'il existe un Manager Class
Dérivé de Employee
qui ajoute des données Salary
et implémente earning()
. Maintenant, Employee
est une classe abstraite mais Manager
est un concrete class
Et vous pouvez donc avoir un objet de Manager
. Mais lorsque vous instancialisez Manager
, vous devez initialiser/affecter des valeurs aux membres hérités de base class i.e. Employee
. Une façon est que vous pouvez avoir setFirstName() & setLastName()
dans la classe de base à cette fin et vous pouvez les utiliser dans le constructeur pour derived class i.e. Manager
Ou une méthode plus pratique serait d'avoir un constructeur dans votre base abstract class Employee
.
Voir le code ci-dessous:
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class Employee {
public:
Employee(const char*, const char*);
~Employee();
const char* getFirstName() const;
const char* getLastName() const;
virtual double earnings() const=0; // pure virtual => abstract class
virtual void print() const;
private:
char* firstname;
char* lastname;
};
Employee::Employee(const char* first, const char* last){
firstname= (char*) malloc((strlen(first)+1)*sizeof(char));
lastname= (char*) malloc((strlen(last)+1)*sizeof(char));
strcpy(firstname,first);
strcpy(lastname,last);
}
Employee::~Employee(){
free(firstname);
free(lastname);
cout << "Employee destructed" << endl;
}
const char* Employee::getFirstName() const{ return firstname;}
const char* Employee::getLastName() const{ return lastname; }
void Employee::print() const{
cout << "Name: " << getFirstName() << " " << getLastName() << endl;
}
class Manager:public Employee{
public:
Manager(char* firstname,char* lastname,double salary):
Employee(firstname,lastname),salary(salary){}
~Manager(){}
double earnings() const {return salary;}
private:
double salary;
};
int main(){
Manager Object("Andrew","Thomas",23000);
Object.print();
cout << " has Salary : " << Object.earnings() << endl;
return 0;
}
"Une classe abstraite contient au moins une fonction virtuelle pure. Vous déclarez une fonction virtuelle pure en utilisant un spécificateur pur (= 0) dans la déclaration d'une fonction membre virtuelle dans la déclaration de classe."
en ce qui concerne:
void Boss::Boss (const char* first, const char* last, double s)
: Employee (first, last)
first
et last
sont définis dans la classe de base. Par conséquent, pour les initialiser, nous devons appeler le constructeur de la classe de base : Employee (first, last)
.
firstName et lastName sont des membres privés, non accessibles à Boss. Toutes les interfaces avec celles-ci doivent être présentes dans la classe Employee, y compris l’initialisation.