web-dev-qa-db-ja.com

C ++抽象クラス:コンストラクターyesまたはno?

1つ(または複数)の仮想純粋関数を持つクラスは抽象的であり、新しいオブジェクトの作成には使用できないため、コンストラクターはありません。

私は次の例を提供する本を読んでいます:

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;
};

クラスが抽象クラスの場合、コンストラクターがあるのはなぜですか?後でこのクラスを使用します(BossEmployeeから派生したパブリックです):

void Boss::Boss (const char* first, const char* last, double s)
     : Employee (first, last)
53
user2452426

純粋な仮想関数を持つクラスが抽象的であり、インスタンス化できないと言うのは正しいことです。しかし、コンストラクタを持つことはできないと言うのは間違っています。

確かに、あなたの例が示すように、抽象クラスはプライベートメンバーを持つことができ、このクラスのメンバー関数によって使用される可能性があります。そして、これらのメンバーは初期化する必要があります。コンストラクターはそれを行う方法です(たとえば、2番目のサンプルが示すように、派生クラスの初期化リストを使用します)。たとえば、私の意見ではinit()関数よりも優れています。

回答のコメントを編集する:抽象クラスはメンバー変数と潜在的に非仮想メンバー関数を持つことができるため、前者から派生したクラスはすべて特定の機能を実装します。

次に、これらのメンバー変数の初期化の責任は、抽象クラス(少なくともプライベートメンバーに常に属します。派生クラスはそれらを初期化できますが、これらのメンバーを使用/依存する可能性のある継承されたメンバー関数を使用できます)。したがって、抽象クラスがコンストラクターを実装することは完全に合理的です。

69
JBL

純粋な仮想関数を持つクラスはインスタンス化できません。それを拡張し、欠落している機能を提供するサブクラスを持つことが期待されています。

これらのサブクラスは、インスタンス化されるときに基本クラスを構築し、スーパークラスのコンストラクターを呼び出します。これが、抽象クラスにc ++のコンストラクターがある理由です。

したがって、インスタンスを直接作成してコンストラクターを直接呼び出すことはできませんが、将来のサブクラスは直接呼び出します。

21
odedsh

Employeeクラスにはデータがあり、このデータは何らかの方法で初期化する必要があります。コンストラクターはそのための良い方法です。

4
Juraj Blaho

基本抽象クラスにコンストラクタがない場合、派生クラスのオブジェクトを作成するときに、派生クラスの_firstname , lastname_メンバーに値をどのように割り当てますか?

Employeeデータを追加し、earning()を実装するSalaryから派生した_Manager Class_があるとします。 Employeeは抽象クラスですが、Managerは_concrete class_であるため、Managerのオブジェクトを持つことができます。ただし、Managerをインスタンス化する場合は、_base class i.e. Employee_から継承したメンバーに値を初期化/割り当てる必要があります。 1つの方法は、この目的のためにsetFirstName() & setLastName()を基本クラスに入れて、_derived class i.e. Manager_のコンストラクターで使用できることです。より便利な方法は、_base abstract class Employee_。

以下のコードを参照してください。

_#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;
}
_
3
Gaurav K

「抽象クラスには少なくとも1つの純粋仮想関数が含まれます。クラス宣言の仮想メンバー関数の宣言で純粋指定子(= 0)を使用して、純粋仮想関数を宣言します。」

に関して:

_void Boss::Boss (const char* first, const char* last, double s)
     : Employee (first, last)
_

firstlastは基本クラスで定義されているため、それらを初期化するには、基本クラスのコンストラクター: Employee (first, last)を呼び出す必要があります。

0
ldgorman

firstNameおよびlastNameはプライベートメンバーであり、ボスにはアクセスできません。初期化を含む、これらのインターフェイスはすべてEmployeeクラスに存在する必要があります。

0
MaHuJa