【问题标题】:Declaring constructors as private shows errors. Is at least one public constructor mandatory?将构造函数声明为私有会显示错误。至少一个公共构造函数是强制性的吗?
【发布时间】:2016-02-23 17:28:09
【问题描述】:

我是 C++ 的学习者。我已经编译了以下程序。我正在研究构造函数和析构函数的概念。我在下面有这段代码,我在其中声明了一个私有析构函数并使用 main() 中的类的成员函数访问私有成员。我知道可以声明私有构造函数,但公共构造函数也是强制性的吗?下面是我的代码:

class Book
{
private:
    int *pages;
    int *price;


    Book()        //default constructor
    {
        pages = new int;
        price = new int;
        *pages = 300;
        *price = 8;
    }

public:
    void pre_destructor()
    {
        std::cout << "The pages:" << *pages << "\n";
        std::cout << "The price:" << *price << "\n";
    }

~Book() //destructor
    {
        std::cout << "The pages:" << *pages << "\n";
        std::cout << "The price:" << *price << "\n";
        delete pages;
        delete price;
    }

};

int main()
{
    using namespace std;
    Book book1;

    cout << "Before using destructors" << endl;
    cout << "---------------------------------"<< endl;

    book1.pre_destructor();

    cout << "After using destructors" << endl;
    cout << "---------------------------------";

    return 1;

}

对于上述程序,显示了两个错误。一个是在声明对象的主函数中;错误:内容中的错误。第二个在调用构造函数的那一行;错误:Book::Book() 是私有的。

主要不是直接访问代码中的构造函数。那为什么会显示访问错误呢?

【问题讨论】:

  • 将构造函数声明为私有不会让对象在其他范围内被创建。由于不能从那里调用构造函数。所以构造函数/析构函数是公开的!
  • 你需要得到a good book
  • The main is not directly accessing the constructor in the code. 也是。 Book book1; 行使用其默认构造函数初始化对象(您将其设为私有,因此无法访问)。
  • 停止使用新的和删除的。这里真的需要动态内存分配吗? main 应该返回 0。为什么要从析构函数访问数据成员?
  • @PravasiMeet:并不是说在析构函数中访问数据成员有什么问题……

标签: c++ c++11 constructor destructor dynamic-memory-allocation


【解决方案1】:

不,public 构造函数不是强制性的。有私有构造函数的用例。

  • 只有静态方法的类可能具有private(或已删除)构造函数以防止创建实例。
  • 单例类(仅存在一个类的实例)可以通过使用private 构造函数来强制执行其单例状态。可以通过 static getter 访问该实例。
  • 您可能希望遵循构建器或工厂模式,强制用户使用除了调用构造器之外的进程来构建实例。该构建器或工厂将是该类的成员或friend,因此能够调用private 构造函数。这种方案在 Java 中比 C++ 更常见,但 C++ 也允许这样做。

也就是说,您只是想构造一个类的实例:

Book book1;

这种用法肯定需要public 默认构造函数。

【讨论】:

  • 这应该被接受为答案。很好的答案。 +1
【解决方案2】:

当您将构造函数设为私有时,您需要公开一个方法,以便外部类/方法可以创建此类的对象。您可以通过创建一个静态方法来实现,该方法反过来创建对象。

以下代码演示:

#include <iostream>
class Book
{
private:
    int *pages;
    int *price;


    Book()        //default constructor
    {
        pages = new int();
        price = new int();
        *pages = 300;
        *price = 8;
    }

public:
    static Book* constructBook() 
    {
        return new Book();
    }

    void pre_destructor()
    {
        std::cout << "The pages:" << *pages << "\n";
        std::cout << "The price:" << *price << "\n";
    }

    ~Book() //destructor
    {
        delete pages;
        delete price;
    }

};

int main()
{
    Book* book1 = Book::constructBook();

    std::cout << "Before using destructors" << endl;
    std::cout << "---------------------------------"<< endl;

    book1->pre_destructor();

    cout << "After using destructors" << endl;
    cout << "---------------------------------";
    delete book1;
    return 0;

}

【讨论】:

    【解决方案3】:

    一点也不!您不需要public constructor,但需要一个工厂函数来创建该类的实例,在这种情况下,您需要使用关键字static 限定该函数。见下文:-

    #include <iostream>
    using namespace std;
    class X
    {
        int x;
        X(int x)
        { 
            cout<<"creation\n";
            this->x = x; 
        }
        public:
        static X make_X (int x) // without static error message will be : error: cannot call member function 'X X::make_X(int)' without object
        {
            return X(x);
        }
        int& getx()
        {
            return x;
        }
        ~X()
        {
            cout<<"destruction\n";
        }
    };
    int main()
    {
        auto obj = X::make_X(5);
        auto ano = X::make_X(7);
        cout << obj.getx() << '\t' << ano.getx() << '\n';
        return 0;
    } 
    

    输出是:-

    creation
    creation
    5   7
    destruction
    destruction
    

    这里不需要公共承包商。但是您需要 make_X 来创建该类的实例。

    您也可以使用friend 代替静态。在这种情况下,代码将是:-

    friend X make_X (int x);  // declare a prototype in the class
    

    然后在类定义之外定义:-

    X make_X (int x)
    {
        return X(x);
    }
    

    这就是它的工作原理!干杯!!

    【讨论】:

    • 停止使用#include 。它不是标准的 C++。它只能在 gcc 编译器中工作,并且使您的程序不可移植。
    • @PravasiMeet 对此表示遗憾,因此我进行了更改
    猜你喜欢
    • 2011-02-08
    • 2017-04-30
    • 1970-01-01
    • 1970-01-01
    • 2021-03-16
    • 2012-10-10
    • 2017-03-17
    • 2016-06-12
    • 2016-12-03
    相关资源
    最近更新 更多