79

具有一个(或多个)虚纯函数的类是抽象的,不能用于创建新对象,因此它没有构造函数。

我正在阅读一本提供以下示例的书:

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

如果类是抽象的,为什么我们有一个构造函数?它稍后使用这个类(Boss是从公共派生的Employee):

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

9 回答 9

93

当您说具有纯虚函数的类是抽象的并且无法实例化时,您是正确的。但是当你说它不能有构造函数时你错了。

实际上,正如您的示例所示,抽象类可以具有私有成员,此类的成员函数可以使用这些成员。并且这些成员必须被初始化。构造函数是一种方法(例如,在派生类中使用初始化列表,如您的第二个示例所示),在我看来比init()函数更好。

在答案中编辑我的评论:抽象类可以具有成员变量和潜在的非虚拟成员函数,以便前者的每个派生类都实现特定功能。

然后,初始化这些成员变量的责任可能属于抽象类(至少总是对于私有成员,因为派生类无法初始化它们,但可以使用一些可能使用/依赖的继承成员函数在这些成员上)。因此,抽象类实现构造函数是完全合理的。

于 2013-11-06T09:52:40.607 回答
31

不能实例化具有纯虚函数的类。预计会有子类来扩展它并提供缺失的功能。

这些子类在实例化时将构造基类,它们将调用其超类的构造函数,这就是抽象类在 c++ 中具有构造函数的原因。

所以你不能直接创建实例并直接调用构造函数,但未来的子类会。

于 2013-11-06T09:55:48.020 回答
8

该类Employee有数据,这些数据需要以某种方式初始化。构造函数是一个很好的方法。

于 2013-11-06T09:49:15.300 回答
6

如果基础抽象类没有构造函数firstname , lastname,当您创建派生类的对象时,您将如何为任何派生类的成员赋值?

假设有一个Manager Class派生的,Employee从中添加Salary数据和实现earning()。NowEmployee是一个抽象类,但Manager它是一个concrete class,因此您可以拥有一个Manager. 但是当你实例化时Manager,你需要初始化/赋值给继承自的成员base class i.e. Employee。一种方法是您可以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;
}
于 2014-05-08T02:42:42.523 回答
1

"An abstract class contains at least one pure virtual function. You declare a pure virtual function by using a pure specifier (= 0) in the declaration of a virtual member function in the class declaration."

regarding:

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

first and last are defined in the base class, therefore, in order to initialize them, we need to make a call to the constructor of the base class : Employee (first, last)

于 2013-11-06T09:55:36.203 回答
1

抽象类是其中至少有一个纯虚函数的类。我们不能实例化一个抽象类。但它可以有构造函数。请参见下面的示例。如果我们不重写派生类中的虚函数,它也会变成一个抽象类,

class Abstract {
private:
    int x, y;
public:
    virtual void a() = 0;//pure virtual function
    Abstract(int x1, int y1) {
        x = x1;
        y = y1;
    }
};

class Base :public Abstract {
private:
    int z;
public:
    Base(int x, int y, int z1) :Abstract(x, y) {
        z = z1;
    }
    void a() {
 }
};

int main() {
    Base b(1, 2, 3);
}
于 2021-06-26T05:51:50.753 回答
0

firstNamelastName是私有成员,Boss 无法访问。所有这些接口都必须存在于 Employee 类中,包括初始化。

于 2013-11-06T09:50:47.607 回答
-1

抽象类的目的是您希望通过派生类扩展某些功能。它可以有构造函数吗?是的,它可以,目的是从基类初始化局部变量。您应该避免在 Abstract 中使用公共构造函数并仅使用 protected。

你的例子不是一个很好的例子。不知道它是什么书,但那是个坏例子。就像用变量“iAmString”的名称定义int变量:)。

int iAmString = 12;

干杯

于 2014-02-28T20:48:38.183 回答
-1

初始化 firstName 和 lastName。否则,您将不得不编写代码在每个派生类的构造函数中初始化它们

于 2013-11-06T09:51:09.890 回答