2010-02-01 81 views
4

當我嘗試編譯如下:公共新的私有構造

#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不用於堆棧對象,所以不允許在堆棧上創建對象。

+0

您可以使用「代碼格式化」按鈕或4個空格的縮進代碼塊,而不是混淆您的代碼的html格式。 – jalf 2010-02-01 17:45:57

+0

我試過了,我只是沒有切割和粘貼的成功。 – doron 2010-02-01 17:52:15

+0

只是好奇,什麼是用例,導致你阻止給定類型的堆棧分配? – 2010-02-01 18:01:56

回答

9

我覺得你有什麼operator new做了誤解。它不創建對象,而是爲對象分配內存。編譯器會在調用新的operator後立即調用構造函數。

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 
} 

操作者新的主要用途是具有存儲器分配器爲系統(通常的malloc)的默認分配器不同的,並且是指以返回的存儲器的未初始化區域在其上的編譯器將調用構造函數。但是在之後,構造函數被稱爲,在寫入新調用的範圍(本例中爲main)中分配了內存。

承兌匯票

完全解決問題配製的經過:我怎麼逼我的類的用戶在堆中實例化?是使構造函數爲私有並提供工廠函數,如其他答案(如villintehaspam指出的那樣)中所示。

+0

有意義,因爲新返回一個void *(即未構造的內存) – doron 2010-02-02 10:46:47

5

new不調用構造函數 - 編譯器會這樣做,並且構造函數必須可以訪問它。把這個簡單的代碼:

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

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

顯然,新的不調用構造函數,但是如果你編譯它,你仍然會得到一個「私有構造函數」錯誤消息..

+2

那麼,這是否以某種方式說明了爲什麼編譯器不能調用私有構造函數? – 2010-02-01 17:54:21

+0

這不是問題。但是,當然私人的構造函數不能被編譯器調用 - 因此這樣做的做法是將複製構造函數設置爲私有的,以防止按值調用。 – 2010-02-01 18:03:58

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 
} 
0

的問題是,如果構造是私有的,你不能實例化一個對象。

爲什麼你讓你的構造函數是私人的?

+0

我想要一個只能在堆上實例化的對象。我希望,因爲新的操作符是類的一部分,它將能夠調用私有構造函數。 – doron 2010-02-01 17:55:15

+0

你可以使用這個工廠類。使其成爲代碼中可以實例化對象的唯一位置。通過在你的'Test'類中嵌套工廠類,即使它是私有的,它也可以調用'new'構造函數。另一種選擇是讓你的工廠類成爲Test類的'朋友'。 – stakx 2010-02-01 18:04:07

+0

看看「命名的構造函數習慣用法」...您只需創建一個公共靜態「Create ...」方法,該方法可以調用您的私有構造函數並僅在堆上創建實例。 – 2010-02-01 18:08:25

10

這是你可以做什麼來強制對象將在堆上創建:

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

,然後當你使用它:

Foo *foo = Foo::Create(); 

你可能要考慮返回一個shared_ptr而不是原始指針來幫助確保對象被刪除。

這在技術上不是你問什麼,但它是你指出什麼,你想實現...

1

由於各種原因嚴重列出的原因,您正在做的事情是行不通的;我ussually實現你的「而不是在棧」的目標的方法是,像這樣

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

我們初始化它的唯一途徑是: HeapOnly * MyObj中= HeapOnly ::的CreateInstance();