能,利用

https://en.cppreference.com/w/cpp/language/new#Placement_new?

en.cppreference.com

例如

struct Foo
{
};

Foo foo;
new (foo) Foo(); // 在原有的 foo 對象上重新構造一個 Foo 類型的對象
// 由於原先的 foo 的存儲被新構造的 Foo 對象重用,原有的 foo 對象生命期終止
// 注意這並不會自動調用原有的 foo 的析構函數,此處是允許的
// 但如果有依賴於 Foo 的析構函數調用的副作用的代碼存在,則行為是未定義的


不能。

印象中課上講過就是不能的,但長期沒想過這個問題有些猶豫所以測試了一下。

如果顯式調用構造函數

class A {
public:
A() {}
};

int main() {
A a;
a.A();
return 0;
}

必定報錯這沒有什麼好質疑的。

然後就想到大一寫過的一種錯誤的代碼:用成員函數再次調用構造函數。

#include &
using namespace std;
class A {
public:
A() {
cout &

編譯能過,而且能輸出兩個constructor function.

於是我初學的時候在很長一段時間認為是可以多次調用構造函數的。

然後剛剛細想了一下,這兩個A是一樣的嗎?

於是輸出了一下對象的地址。

#include &
using namespace std;
class A {
public:
A() {
cout &

發現,雖然表面上輸出了兩個constructor function,但他們所屬的對象並不一樣。

vs2019 x64環境下輸出如圖。

突然恍然大悟,

平時創建對象通常這麼寫

string str("hello, world");

因為這樣更符合C++的味道,另一種寫法自己似乎忘記了。

string str = string("hello, world");

構造函數string(const char *t);接收"hello,world"參數,創建了一個對象,並且這個對象的標識符叫做str。

注意:這句代碼僅調用了 string(const char*t)這個構造函數,沒有調用拷貝構造函數,也沒有調用operator = 的重載。所以準確來講,並不是A()創建了一個對象並將對象返回賦值給str,而是創建的對象就叫str。可以自己下去試試此處就不延伸了。

所以結果顯而易見。第三行輸出的this值和第一行不一樣,所以cout &

故,一個對象,構造函數只能調用一次。


不能,在定義對象的時候就已經調用了構造函數,以後不能再調用構造函數。

@夏之幻想 給出的placement new的用法不能算是調用該對象的構造函數,只是原址構建一個新的對象,本質上已經變了!

如果需要在創建對象後再初始化對象,考慮提供init函數。


class A {
public:
A(){
cout &

vc++ 可以,不過建議用轉發構造函數實現你的功能。


c++沒有顯式調用一個對象的構造函數的語法, 甚至連獲取構造函數的地址都是不可能的:

https://zh.cppreference.com/w/cpp/language/initializer_list?

zh.cppreference.com

但是... 在沒有優化的情況下, g++也會把構造函數當作普通函數來處理, 同時, 在代碼里的位置相鄰的兩個函數在生成的代碼里也會是相鄰的; 所以, 可以多定義一個函數, 把這個函數的地址減去構造函數的大小, 就是構造函數的地址了:

#include &

struct A
{
int v;
A(int i) : v(i) { printf("A constructor
"); }
void p() { printf("%d
", v); }
};

template&
union adapter
{
T origin;
char *bytes;
void (*ctor)(A*, int);
adapter(T v) : origin(v) {}
};
template&
adapter(T) -&> adapter&;

int main()
{
adapter ctor(A::p);
ctor.bytes -= 40;
A a(5);
a.p();
ctor.ctor(a, 12);
a.p();
return 0;
}

輸出, 很明顯構造函數被調用了兩次


不能了,因為類的對象在定義的時候,已經調用了構造函數。

你可以把你需要的其他的操作寫到另外的一個函數里,在類的對象定義完成以後,進行調用。


推薦閱讀:
相关文章