1)不论是只能在堆上创建对象、只能在栈上创建对象,构造函数必须得封死。如果不封死构造函数,在任何地方均可创建对象,包括在类外也能够创建对象。
class Stack {
private:
Stack(){} // 封死构造函数
};
int main() {
system("pause");
return 0;
}
2)现在也无法再任何地点创建对象。需要提供静态方法,供创建栈上对象,在方法内创建对象,Stack s; return &s;但是该函数在函数体内创建出局部变量,返回一个局部变量出来。但是实质上是值拷贝,当函数需要返回一个对象,他会在栈中创建一个临时对象,存储函数的返回值。即拷贝出一个临时的匿名对象出来,放在外部的函数栈帧当中。匿名对象创建出就立马进行返回了,在编译器返回时遇到匿名对象时会做优化,直接调用一次构造函数,在外部创建一个对象。
class Stack {
public:
static Stack GetStack() { // 静态方法
Stack s; // 在栈上生成对象
return s; // 返回发生值拷贝
}
Stack(const Stack& s) { // 拷贝构造
cout << "Stack(const Stack& s)" << endl;
}
private:
Stack() {
cout << "Stack()" << endl;
}
};
int main() {
Stack s = Stack::GetStack();
system("pause");
return 0;
}
即先函数内部调用构造函数,返回时再调用拷贝构造函数。
class Stack {
public:
static Stack GetStack() {
// Stack s;
return Stack(); // 写成匿名对象形式,Stack()相当于调用构造函数,
// 创建一个匿名对象再返回,编译器的内部优化
}
Stack(const Stack& s) {
cout << "Stack(const Stack& s)" << endl;
}
private:
Stack() {
cout << "Stack()" << endl;
}
};
int main() {
Stack s = Stack::GetStack();
system("pause");
return 0;
}
return返回时编译器调用构造函数,并且马上进行返回,即编译器进行内部优化,创建匿名对象直接进行返回,少调用一次拷贝构造,提高效率。
3)在此思考,拷贝构造需要封死吗?大可不必这么敏感,保持清醒头脑,切勿草木皆兵啊。答案是不必的,因为拷贝构造出来的对象仍然在栈上啊,并且函数在返回时也调用了拷贝构造的!
4)C++11新写法,直接将operator new只声明不实现
class Stack {
void* operator new(size_t n) = delete;
private:
// void* operator new(size_t n);
};
int main() {
Stack s = Stack::GetStack();
system("pause");
return 0;
}
对于这种写法来讲,再调用new是无法调用的,因为new底层也是依靠operator new实现的。malloc可以操作,但是malloc是创建对象吗?malloc只是申请空间,算作是一个小bug吧。但是却可以在类外部直接创建对象
class Stack {
// void* operator new(size_t n) = delete;
public:
void* operator delete(void* p) = delete;
private:
void* operator new(size_t n);
void* operator delete(void* p);
};
// 构造函数仍然公有
Stack s; // 在数据段仍然可以创建对象
int main() {
Stack* p = new Stack(); // new 只声明不实现,调不动
delete p; // delete只声明不实现,也调不动
//Stack* ps = (Stack*)malloc(sizeof(Stack)); // 先利用malloc申请空间
//new(ps) Stack; // 再调new的定位表达式,调构造函数,但是构造函数私有无法调动
system("pause");
return 0;
}
综上所述:还是推荐写上面那种方式,下面采用C++11新语法封死operator new的方式,其既可以在栈上创建对象,还可以在数据段创建对象。且注意C++11未封死构造函数,构造函数公有。