C++ 抽象类:构造函数是或否?

Posted

技术标签:

【中文标题】C++ 抽象类:构造函数是或否?【英文标题】:C++ Abstract Class: constructor yes or no? 【发布时间】:2013-11-17 11:43:30 【问题描述】:

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

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

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)

【问题讨论】:

你的第一句话不正确,被代码示例否定了。你到底在问什么? 我认为这会有所帮助:***.com/questions/9399290/… 【参考方案1】:

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

【讨论】:

我能否建议您解释一下如何/在什么情况下调用构造函数?我认为这让提问者感到困惑。 @Azendale 您可以通过初始化列表在派生具体类的构造函数中调用它。 MyClass(const char *firstName, const char *lastName) : Employee(firstName, lastName) 【参考方案2】:

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

【讨论】:

【参考方案3】:

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

【讨论】:

【参考方案4】:

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

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

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

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

【讨论】:

谢谢大家。所以一个抽象类不能被实例化,但它可以有一个构造函数......好吧......现在我清楚了。但是想知道为什么在上面的例子中基类的数据成员(名字和姓氏)被指定为私有而不是受保护的。为了保持封装?再次感谢 是的!如您所见,抽象类仍然可以具有成员和/或非纯虚成员函数(例如,以确保每个派生类都提供特定功能)。这并不意味着派生类(或在多态的情况下操作指向抽象类实例的指针)应该知道该特性的实现细节。【参考方案5】:

“一个抽象类至少包含一个纯虚函数。您可以通过在类声明中的虚成员函数声明中使用纯说明符 (= 0) 来声明纯虚函数。”

关于:

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

firstlast是在基类中定义的,因此,为了初始化它们,我们需要调用基类: Employee (first, last)的构造函数

【讨论】:

IBM Abstract classes (C++ only)【参考方案6】:

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

这些子类在实例化时会构造基类,它们会调用超类的构造函数,这就是为什么抽象类在 c++ 中有构造函数。

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

【讨论】:

【参考方案7】:

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

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

int iAmString = 12;

干杯

【讨论】:

"你应该避免在 Abstract 中使用公共构造函数,而只使用 protected。" 为什么?在派生类之外意外调用构造函数是没有危险的,它会导致编译器错误。 “你应该..”没有给出理由是不好的恕我直言【参考方案8】:

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

假设有一个从Employee 派生的Manager Class,它添加了Salary 数据并实现了earning()。现在Employee 是一个抽象类,但Managerconcrete 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;

【讨论】:

【参考方案9】:

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

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

【讨论】:

以上是关于C++ 抽象类:构造函数是或否?的主要内容,如果未能解决你的问题,请参考以下文章

C++ 未定义的抽象类构造函数

无法实例化抽象类我认为我搞砸了我的构造函数 C++

接受对抽象类的 const 引用的 C++ 构造函数无法初始化 std::map

在其派生类C++的构造函数中调用基类的构造函数[重复]

来自基类的 c++ 构造函数

在c++中如何用new生成一个构造函数带参数的类数组?