代码之家  ›  专栏  ›  技术社区  ›  doron

公共新私有构造函数

c++
  •  4
  • doron  · 技术社区  · 14 年前

    当我尝试编译以下内容时:

    #include <iostream>
    
    class Test
    {
    public:
        void* operator new (size_t num);
        void operator delete (void* test);
        ~Test();
    private:
        Test();
    };
    
    Test::Test()
    {
        std::cout << "Constructing Test" << std::endl;
    }
    
    Test::~Test()
    {
        std::cout << "Destroying Test" << std::endl;
    }
    
    void* Test::operator new (size_t num)
    {
        ::new Test;
    }
    
    void Test::operator delete(void* test)
    {
        ::delete(static_cast<Test*>(test));
    }
    
    int main()
    {
        Test* test = new Test;
        delete test;
    }
    

    我得到:

    $ g++ -o test test.cpp
    test.cpp: In function ‘int main()’:
    test.cpp:14: error: ‘Test::Test()’ is private
    test.cpp:36: error: within this context
    

    如果新函数是成员函数,为什么不能调用私有构造函数?

    编辑: 我的想法是创建一个类,该类只能使用完全标准的语法在堆上实例化。我希望,因为new是一个数据成员,所以它可以调用私有构造函数,但是由于new不用于堆栈对象,所以不允许您在堆栈上创建对象。

    6 回复  |  直到 6 年前
        1
  •  9
  •   Community Egal    7 年前

    我想你对 operator new 做。它不创建对象,而是为对象分配内存。编译器将在调用运算符new后立即调用构造函数。

    struct test {
       void * operator new( std::size_t size );
    };
    int main()
    {
       test *p = new test;
       // compiler will translate this into:
       //
       // test *p = test::operator new( sizeof(test) );
       // new (static_cast<void*>(p)) test() !!! the constructor is private in this scope
    }
    

    new运算符的主要用法是使用一个不同于系统默认分配器的内存分配器(通常是malloc),它的目的是返回一个未初始化的内存区域,编译器将在该区域调用构造函数。但是构造函数被称为 之后 内存分配在写入新调用的作用域中(在本例中为main)。

    验收单后

    对未表述问题的完整解决方案: 如何强制类的用户在堆中实例化? 是使构造函数私有化并提供工厂功能,如其他一些答案所示(如 villintehaspam 指出。

        2
  •  10
  •   villintehaspam    14 年前

    您可以这样做来强制在堆上创建对象:

    class Foo {
    public:
        static Foo *Create() {
             return new Foo;
        }
    private:
        Foo() {}
    };
    

    然后当你使用它时:

    Foo *foo = Foo::Create();
    

    您可能需要考虑返回共享指针而不是原始指针,以帮助确保对象被删除。

    从技术上讲,这不是你所要求的,而是你所表示的你想要实现的……

        3
  •  5
  •   anon    14 年前

    new不调用构造函数-编译器调用,构造函数必须可以访问它。取这个简单的代码:

    class A {
        A() {}
    public:
        void * operator new( size_t x ) { return 0; }
    };
    
    int main() {
        A* a = new A;
    }
    

    显然,new没有调用构造函数,但是如果编译它,仍然会收到一条“私有构造函数”错误消息。

        4
  •  1
  •   Elemental    14 年前

    由于各种各样的人都不清楚你所做的事情是行不通的,我过去实现你“不在堆栈上”目标的方式是这样的。

    class HeapOnly {
      public:
        static HeapOnly* CreateInstance() { return new HeapOnly(); }
      protected:
        HeapOnly() { }
    };
    

    现在唯一实例化它的方法是: heapOnly*myObj=heapOnly::createInstance();

        5
  •  1
  •   stakx - no longer contributing Saravana Kumar    14 年前

    在这方面,构造函数实际上与其他成员函数没有什么不同:如果它们被标记为 private 它们在类之外是不可访问的(例如 main )因为,在实例化期间,构造函数 总是 需要调用,不能实例化仅具有 私有的 (即不可接近)施工人员。

    现在,即使您没有声明任何构造函数 你自己 C++编译器将提供某些默认构造函数,甚至提供默认赋值操作符。 = :

    • 默认构造函数(没有参数): Test::Test()
    • 复制构造函数(采用类类型的对象引用): Test::Test(const Test&)
    • 分配运算符 = 以下内容: Test& Test::operator =(const Test&)

    而这正是 私有的 构造函数很有用:有时,您不希望类具有所有这些隐式实现,或者不希望类支持某些行为,如复制分配或复制构造。在这种情况下,您将那些您不希望用于类的成员声明为 私有的 ,例如:

    class Test
    {
    private:
        Test(Test& init) { }  // <-- effectively "disables" the copy constructor
    }
    
        6
  •  0
  •   Liz Albin    14 年前

    问题是,如果构造函数是私有的,则不能实例化对象。

    为什么要将构造函数设置为私有?