公共新的私有构造函数

时间:2010-02-01 17:41:43

标签: c++

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

#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是一个数据成员,它可以调用私有构造函数,但由于new不用于堆栈对象,所以不允许在堆栈上创建对象。

6 个答案:

答案 0 :(得分:10)

这是强制在堆上创建对象的方法:

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

然后当你使用它时:

Foo *foo = Foo::Create();

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

这在技术上并不是你所要求的,但这是你表示你希望实现的......

答案 1 :(得分:9)

我认为你对operator new的作用有误解。它不会创建对象,而是为对象分配内存。编译器将在调用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
}

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

接受通知后

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

答案 2 :(得分:5)

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

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

int main() {
    A* a = new A;
}

显然,new不会调用构造函数,但如果编译它仍然会出现“私有构造函数”错误消息..

答案 3 :(得分:1)

在这方面,构造函数与其他成员函数没有什么不同:如果它们被标记为private,则它们在类外无法访问(例如在main中)。而且,因为在实例化过程中,需要调用构造函数 ,所以不能实例化只有private(即不可访问)构造函数的类的对象。

现在,即使您没有自己声明任何构造函数 ,C ++编译器也会提供某些默认构造函数,甚至是默认赋值运算符=

  • 默认构造函数(没有参数):Test::Test()
  • 复制构造函数(获取类类型的对象引用):Test::Test(const Test&)
  • 赋值运算符=Test& Test::operator =(const Test&)

这正是private构造函数有用的地方:有时,您不希望您的类具有所有这些隐式实现,或者您不希望您的类支持某些行为,例如复制赋值或复制建设。在这种情况下,您将那些您不想要的课程成员声明为private,例如:

class Test
{
private:
    Test(Test& init) { }  // <-- effectively "disables" the copy constructor
}

答案 4 :(得分:1)

由于各种人员严重勾勒的原因,你所做的事情是行不通的;我实际上实现你的“不在堆叠”目标的方式是这样的

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

现在实例化它的唯一方法是:     HeapOnly * MyObj = HeapOnly :: CreateInstance();

答案 5 :(得分:0)

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

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