C++中何时需要使用私有构造函数?

66

我有一个关于C++中私有构造函数的问题。如果构造函数是私有的,那么如何创建该类的实例?

我们是否需要在类内部添加getInstance()方法?

9个回答

72

有几种情况需要使用 private 构造函数:

  1. Restricting object creation for all but friends; in this case all constructors have to be private

    class A
    {
    private:
       A () {}
    public:
       // other accessible methods
       friend class B;
    };
    
    class B
    {
    public:
       A* Create_A () { return new A; }  // creation rights only with `B`
    };
    
  2. Restricting certain type of constructor (i.e. copy constructor, default constructor). e.g. std::fstream doesn't allow copying by such inaccessible constructor

    class A
    {
    public:
       A();
       A(int);
    private:
       A(const A&);  // C++03: Even `friend`s can't use this
       A(const A&) = delete;  // C++11: making `private` doesn't matter
    };
    
  3. To have a common delegate constructor, which is not supposed to be exposed to the outer world:

    class A
    {
    private: 
      int x_;
      A (const int x) : x_(x) {} // common delegate; but within limits of `A`
    public:
      A (const B& b) : A(b.x_) {}
      A (const C& c) : A(c.foo()) {}
    };
    
  4. For singleton patterns when the singleton class is not inheritible (if it's inheritible then use a protected constructor)

    class Singleton
    {
    public:
       static Singleton& getInstance() {
          Singleton object; // lazy initialization or use `new` & null-check
          return object;
       }
    private:
       Singleton() {}  // make `protected` for further inheritance
       Singleton(const Singleton&);  // inaccessible
       Singleton& operator=(const Singleton&);  // inaccessible
    };
    

6
如果这个类设计成只能被子类继承和使用,那么实际上它可以是一个“protected static”的类。 - larsmoa
1
我不理解@larsm评论中的“赞同”。它没有意义。 - Cheers and hth. - Alf
1
@Alf:现在不是了,但之前它说“必须是公共静态的”。 - larsmoa
帖子中每个情况都有示例会更好。 - mrgloom
另一个原因可能是我们不想创建可复制的对象。不制作可复制对象的原因可能是为了避免浅拷贝。 - Abhinav Kinagi
虽然已经晚了10年,但对于getInstance()方法来说,应该是static Singleton object而不是Singleton object - Peter

19

私有构造函数通常与Builder方法一起使用,例如在命名构造函数语法中。

class Point
{
public:
  static Point Polar(double, double);
  static Point Cartesian(double, double);
private:
  Point(double,double);
};
在这个(典型的)例子中,使用了命名构造函数惯用法来明确构建Point对象所使用的坐标系。

True。详细示例可在此处找到:(https://isocpp.org/wiki/faq/ctors#named-ctor-idiom) - uutsav
4
这是我所知道的最常见情况。Builder方法的另一个术语是静态工厂方法 - kevinarpe

14

私有构造函数在你想控制类对象创建时非常有用。

让我们来看看代码:

#include <iostream>
using namespace std;

class aTestClass
{
    aTestClass() ////////// Private constructor of this class
    {
        cout << "Object created\n";
    }
    public:

};

int main()
{
    aTestClass a;
    aTestClass *anObject;
}

aTestClass a这行代码会导致错误,因为它间接地尝试访问私有构造函数。注释掉此行并运行程序,程序将完全正常运行。现在的问题是如何在这种情况下创建对象。让我们写另一个程序。

#include <iostream>
using namespace std;

class aTestClass
{
    aTestClass() ////////// Private constructor of this class
    {
        cout << "Object created\n";
    }
    public:

    aTestClass* getAnObject() ///// A public method create an object of this class and return the address of an object of that class
    {
        return (new aTestClass);
    }
};

int main()
{
    //aTestClass a;
    aTestClass *anObject = NULL;
    anObject = anObject->getAnObject();
}

输出结果为

Object created

我们已经创建了一个包含私有构造函数的类的对象。

使用这个概念来实现单例模式。


4

是的,这在单例模式中很常用,对象可以通过静态成员函数访问。


2

如果某个构造函数是私有的,那么意味着只有该类本身(和友元)才能使用该构造函数创建实例。因此,您可以提供像getInstance()这样的静态方法来创建类的实例,或在某个友元类/方法中创建实例。


2

这取决于构造函数最初为什么被设置为私有(您应该询问正在编辑的类的作者)。有时,构造函数可能会被设置为私有以禁止复制构造(同时允许通过其他构造函数进行构造)。其他情况下,构造函数可能会被设置为私有,以禁止除类的“友元”之外的任何人创建该类(如果该类是一个“辅助类”,只应由为该辅助类创建而设计的类使用)。构造函数也可以被设置为私有,以强制使用(通常是静态的)创建函数。


1
如果您创建了私有构造函数,则需要在类内部创建对象。
#include<iostream>
//factory method
using namespace std;
class Test
{
 private:
 Test(){
 cout<<"Object created"<<endl;
}
public:
    static Test* m1(){
        Test *t = new Test();
        return t;
    }
    void m2(){
        cout<<"m2-Test"<<endl;
    }
};
int main(){
 Test *t = Test::m1();
 t->m2();
 return 0;
}

0
我将其与返回std::optional的friend函数结合使用,以便在构造对象时安全地避免异常。例如:
#include <optional>

class Object {
private:
    Object(...) { /* ... */ }

    friend std::optional<Object> make_object(...);
};

std::optional<Object> make_object(...)
{
    // ...
    if (error)
        return std::nullopt;

    // else
    return std::make_optional<Object>(...);
}

然后像这样使用它:

bool f()
{
    auto opt_obj = make_object(...);
    if (!opt_obj)
        return false;

    // else
    auto obj = *std::move(opt_obj);  // API magic

    // ...

    return true;
}

0

C++中的私有构造函数可用于限制常量结构的对象创建。您可以在同一作用域内定义类似的常量,例如枚举:

struct MathConst{
    static const uint8 ANG_180 = 180;
    static const uint8 ANG_90  = 90;

    private:
        MathConst(); // Restricting object creation
};

像这样访问:MathConst::ANG_180


1
这样做的目的被名称空间所击败了,你可以用命名空间替换 struct ,一切都会正常工作,并且更加简洁。 - Xeverous

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接