公有的新私有构造函数

5

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

#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;
}

I get :

$ 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不用于堆栈对象,因此您将无法在堆栈上创建对象。

不要为了你的代码而纠结于HTML格式,只需使用“代码格式化”按钮或用4个空格缩进代码块即可。 - jalf
我尝试过剪切和粘贴,但是没有成功。 - doron
只是好奇,是什么使用情况导致您阻止给定类型的堆栈分配? - David Rodríguez - dribeas
5个回答

11

如果你想将对象放在堆上创建,可以采用以下方法:

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

然后当你使用它时:

Foo *foo = Foo::Create();

你可能希望考虑返回shared_ptr而不是原始指针,以帮助确保对象被删除。

这技术上并不是你所要求的内容,但却是你想要实现的。


11

我认为你对operator new的作用有误解。它不会创建对象,而是为对象分配内存。编译器在调用operator 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)。此外,如何强制用户在堆中实例化我的类?

这是有道理的,因为new返回一个void*(即未构造的内存)。 - doron

5

new不会调用构造函数 - 编译器会调用,而且构造函数必须对编译器可访问。看下面这个简单的代码:

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

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

显然,new 不会调用构造方法,但如果编译它,仍然会得到“私有构造函数”错误消息。

2
那么,这是否说明了为什么私有构造函数无法被编译器调用呢? - user123456
那不是问题所在。但是私有构造函数当然不能被编译器调用 - 因此将复制构造函数设为私有以防止按值调用的做法就很常见了。 - anon

1
由于各种人的解释不够清晰,你所做的事情无法实现;我通常实现“不在堆栈上”的目标的方法如下:
class HeapOnly {
  public:
    static HeapOnly* CreateInstance() { return new HeapOnly(); }
  protected:
    HeapOnly() { }
};

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


0
问题在于如果构造函数是私有的,你就无法实例化一个对象。
为什么你将构造函数设置成了私有的呢?

我想要一个只能在堆上实例化的对象。我希望由于new运算符是类的一部分,它将能够调用私有构造函数。 - doron
看看“命名构造函数惯用法”……你只需创建一个公共静态的“Create…”方法,该方法可以调用您的私有构造函数并仅在堆上创建实例。 - user123456
问题在于,类外部的作用域(实例化的位置)无法调用构造函数,因为它是私有的。既然你只想在堆上构造对象,那么可以编写一个 Create() 或 Clone() 方法。或者你可以使用智能指针。 - Liz Albin

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