C++ Classe abstraite: constructeur oui ou non?
une classe avec une (ou plusieurs) fonctions virtuelles pures est abstraite, et elle ne peut pas être utilisée pour créer un nouvel objet, donc elle n'a pas de constructeur.
je suis en train de lire un livre qui donne 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 nous avons un constructeur? Il utilise cette classe plus tard (Boss
public est dérivé de Employee
):
void Boss::Boss (const char* first, const char* last, double s)
: Employee (first, last)
8 réponses
Vous avez raison quand vous dites qu'une classe qui a une fonction virtuelle pure est abstraite et ne peut pas être instanciée. Mais vous vous trompez quand vous dites qu'il ne peut pas avoir un constructeur.
en effet, comme votre exemple le montre, une classe abstraite peut avoir des membres privés, qui peuvent être utilisés par les fonctions membres de cette classe. Et ces membres doivent être initialisés. Un constructeur est une façon de le faire (par exemple, avec une liste d'initialisation dans la classe dérivée, comme votre deuxième exemple montre), de mieux en mon avis qu'un init()
fonction par exemple.
Modifier mon commentaire dans la réponse: une classe abstraite peut avoir des variables membres et potentiellement des fonctions membres 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 peuvent appartenir à la classe abstraite (au moins, toujours privé pour les membres, parce que la classe dérivée ne être en mesure de les initialiser, mais pourrait utiliser certaines fonctions membres héritées qui peuvent utiliser/compter sur ces membres). Ainsi, il est parfaitement raisonnable pour des classes abstraites de mettre en œuvre des constructeurs.
une classe avec une fonction purement virtuelle ne peut pas être instanciée. On s'attend à ce qu'il comporte des sous-classes qui l'étendront et fourniront les fonctionnalités manquantes.
ces sous-classes construiront la classe de base quand elles seront instanciées, elles appelleront le constructeur de leur super classe, c'est pourquoi les classes abstraites ont des constructeurs en c++.
donc vous ne pouvez pas créer une instance directement et appeler le constructeur directement mais les sous-classes futures le feront.
Employee
classe a données et ces données doit être initialisé en quelque sorte. Le constructeur est un bon moyen de le faire.
si la classe abstract de base n'a pas de constructeur, comment assigneriez-vous des valeurs à firstname , lastname
membres pour toute classe dérivée, lorsque vous créez un objet de la classe dérivée?
supposons qu'il y ait un Manager Class
dérivé de Employee
ajoute Salary
données et met en œuvre earning()
. Maintenant Employee
est une classe abstraite mais Manager
est un concrete class
et donc vous pouvez avoir un objet de Manager
. Mais quand vous êtes instantialting Manager
, vous devez initialiser/assigner des valeurs pour les membres hérités d' base class i.e. Employee
. Une façon est que vous pouvez avoir setFirstName() & setLastName()
dans la classe de base à cet effet et vous pouvez les utiliser dans le constructeur derived class i.e. Manager
ou de façon 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;
}
prénom et nom sont des membres privés, non accessibles au patron. Toutes les interfaces avec ceux - ci doivent être présentes dans la classe des employés, y compris l'initialisation.
"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 de membre virtuel dans la déclaration de classe."
sujet:
void Boss::Boss (const char* first, const char* last, double s)
: Employee (first, last)
first
et last
sont définies dans la classe de base, par conséquent, afin de les initialiser, nous avons besoin de faire un appel au constructeur de la classe de base : Employee (first, last)
Pour initialiser firstName et lastName. Sinon, vous devrez écrire un code pour les initialiser dans les constructeurs de chaque classe dérivée
le but de la classe abstraite est que vous voulez étendre certaines fonctionnalités par des classes dérivées. Peut-il y avoir de constructeur? Oui, il peut et le but est d'initialiser les variables locales de la classe de base. Vous devez éviter D'utiliser le constructeur public dans L'abstrait et utiliser protégé seulement.
L'exemple que vous avez n'est pas un bon exemple. Je ne sais pas quel livre il est, mais que le mauvais exemple. C'est comme définir une variable int avec le nom de la variable "iAmString" :).
int iAmString = 12;
Cheers