这几乎是一个重复的问题,但我真的不明白为另一个问题给出的答案,所以我将再试一次:
我正在学习C ++而我正试图理解创建和使用构造函数的各种选项。所以我的第一个问题是这两个对象创作之间的区别是什么:
class Example{
Example(int x){myX = x} ;
private:
int myX;
}
然后在我的主要方法中:
Example example1 = new Example(5);
Example example2 = Example(5);
Example example3(5);
我知道使用new
会给我一个动态分配的对象,我稍后需要删除它。并且example2
将在堆栈上分配,不需要删除。但我真的不明白何时或为什么要使用example3
的构造函数样式。任何涉及最小术语的帮助都会非常感激,因为这就是为什么我似乎无法在别处理解这一点。非常感谢您提供的任何光线,你们可能会为我提供这些。
答案 0 :(得分:9)
两个声明
Example example2 = Example(5);
Example example3(5);
是等价的。虽然第一个看起来像它可能会创建一个对象,然后调用复制构造函数,但大多数编译器只会创建example2
对象。
关于何时选择使用上述哪种款式的决定很大程度上取决于品味。
这是一个完整的示例程序,用于演示:
#include <iostream>
using namespace std;
class Test {
public:
Test(int x): X(x) {
cout << "constructor " << X << endl;
}
Test(const Test &rhs): X(rhs.X) {
cout << "copy " << X << endl;
}
Test &operator=(const Test &rhs) {
X = rhs.X;
cout << "assign " << X << endl;
return *this;
}
private:
int X;
};
int main()
{
Test t1 = Test(1);
Test t2(2);
t2 = t1;
}
和输出(gcc 4.2.1,OS X Lion):
constructor 1
constructor 2
assign 1
注意如何仅为t2 = t1
调用赋值运算符(如预期的那样),但根本不调用复制构造函数。 (但是,正如Dennis Zickefoose在评论中指出的那样,复制构造函数必须可访问。尝试在上面的示例中创建复制构造函数private
,编译器应该拒绝编译它。)
编辑:请注意,gcc
实际上有一个控制此行为的选项:
-fno-elide-constructors The C++ standard allows an implementation to omit creating a temporary which is only used to initialize another object of the same type. Specifying this option disables that optimization, and forces G++ to call the copy constructor in all cases.
答案 1 :(得分:2)
Example example1 = new Example(5);
由于new Example(5)
返回Example
上的指针,因此不会编译。正确的用法是Example * example1 = new Example(5)
。之后需要删除。
Example example2 = Example(5);
这个创建一个临时的Example实例,并使用(在您的情况下)默认的复制构造函数将其复制到example2。
Example example3(5);
这个在堆栈上创建一个Example实例并调用你的构造函数。
答案 2 :(得分:0)
同时执行
className Object = className(10);
className Object(10);
我相信实际上是等同的。这只是个人偏好。
另一方面,使用new
创建对象除了在堆上分配之外,实际上返回指向创建对象的指针。
Example* example1 = new Example(2);
谈到删除,所有这些都将调用相同的类析构函数。
答案 3 :(得分:0)
当你有一个隐式构造函数时,你可以这样做:
class Example{
public:
Example(int x = 0):x(myX){} ; // use initialization list
private:
int myX;
};
Example example3(5); // ok
Example example3 = 5; // ok
请注意,我定义的 的构造函数用作默认构造函数。
更具体地说,示例3中的构造函数样式通常是构造函数是显式的情况。
class Example{
public:
explicit Example(int x = 0):x(myX){} ; // use initialization list
private:
int myX;
};
Example example3(5); // ok
Example example3 = 5; // not allowed
您可能希望阅读此FAQ以获取有关在构造函数中使用初始化列表的更多信息。