【问题标题】:C++ Abstract Class: constructor yes or no?C++ 抽象类:构造函数是或否?
【发布时间】: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)

【问题讨论】:

标签: c++ class constructor abstract


【解决方案1】:

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

【讨论】:

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

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

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

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

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

      【讨论】:

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

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

      关于:

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

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

      【解决方案6】:

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

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

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

      【讨论】:

        【解决方案7】:

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

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

        int iAmString = 12;

        干杯

        【讨论】:

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

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

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

        【讨论】:

          【解决方案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);
          }
          

          【讨论】:

            猜你喜欢
            • 2023-03-04
            • 2011-08-01
            • 2018-06-10
            • 2015-11-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-04-01
            相关资源
            最近更新 更多