类似这样的问题千奇百怪。例如:
- 为什么我明明不想复制对象,而编译器却偏偏这么做了呢?
- 如何关闭复制机制?
- 如何防止隐式转换?
- 为何 int 自动转换成了复数?
类的默认复制构造函数和赋值运算符可以复制所有元素。例如:
struct Point {
int x,y;
Point(int xx = 0, int yy = 0) :x(xx), y(yy) { }
};
Point p1(1,2);
Point p2 = p1;
至此,p2.x==p1.x 并且 p2.y==p1.y。这可能正是你想要的(而且也是为了和 C 兼容所必需的),但是,以下代码:
class Handle {
private:
string name;
X* p;
public:
Handle(string n)
:name(n), p(0) { /* acquire X called "name" and let p point to it */ }
~Handle() { delete p; /* release X called "name" */ }
// ...
};
void f(const string& hh)
{
Handle h1(hh);
Handle h1 = h2; // 会引起灾难!
// ...
}
在此,默认复制构造函数使得 h2.name==h1.name 并且 h2.p==h2.p。这将导致一场灾难:当函数 f() 运行结束时,会调用 h1 和 h2 的析构函数,这就导致 h1.p 和 h2.p 所指向的对象被 delete 了两次。
如何避免这场灾难?最简单的办法是,将复制构造函数和赋值运算符声明为私有成员,从而关闭复制机制:
class Handle {
private:
string name;
X* p;
Handle(const Handle&); // 阻止复制
Handle& operator=(const Handle&);
public:
Handle(string n)
:name(n), p(0) { /* acquire the X called "name" and let p point to it */ }
~Handle() { delete p; /* release X called "name" */ }
// ...
};
void f(const string& hh)
{
Handle h1(hh);
Handle h1 = h2; // 编译器报错
// ...
}
如果需要复制机制,我们可以定义自己的复制构造函数和赋值运算符,让它们按我们期待的那样工作。
现在回过头来再看看类 Point。对 Point 来说,可以使用默认的复制机制,但它的构造函数有点问题:
struct Point {
int x,y;
Point(int xx = 0, int yy = 0) :x(xx), y(yy) { }
};
void f(Point);
void g()
{
Point orig; // 使用默认值 (0,0) 创建 orig
Point p1(2); // 使用 yy 的默认值 (0) 来创建 p1
f(2); // 调用 Point(2,0);
}
为了便于创建对象(如这里的 orig 和 p1),我们为 Point 的构造函数提供了默认参数。然后,有些人会感到惊讶的事情发生了:调用 f() 时,2 会转换成 Point(2,0)。当我们定义一个接受单个参数的构造函数时,同时亦定义了一种类型转换方式。默认情况下,类型转换是隐式进行的。若想把类型转换改成 显式进行,就要将构造函数声明为 explicit:
struct Point {
int x,y;
explicit Point(int xx = 0, int yy = 0) :x(xx), y(yy) { }
};
void f(Point);
void g()
{
Point orig; // 使用默认值 (0,0) 创建 orig
Point p1(2); // 使用 yy 的默认值 (0) 来创建 p1
// 显式调用构造函数
f(2); // 错误(试图进行隐式转换)
Point p2 = 2; // 错误(试图进行隐式转换)
Pont p3 = Point(2); // 正确(显式转换)
}
原文地址:http://www.research.att.com/~bs/bs_faq2.html#explicit-ctor
分享到:
相关推荐
所以构造函数不能是虚函数。 2. 从使用角度,虚函数主要用于在信息不全的情况下,能使重载的函数得到对应的调用。构造函数本身就是要初始化实例,那使用虚函数也没有实际意义呀。所以构造函数没有必要是虚函数。虚...
详细介绍了构造函数、复制构造函数、拷贝构造函数之间的区别
每个类都具有构造函数和析构函数。其中,构造函数在定义对象时被调用,析构函数在对象释放时被调用。如果用户没有提供构造函数和析构函数,系统将提供默认的构造函数和析构函数。 1.构造函数 构造函数是一个与类同名...
没有合适的默认构造函数,默认构造函数怎么写?为什么这样写?没有写赋值构造函数
构造函数不能声明为虚函数,析构函数可以声明为虚函数。
c#析构构造函数c#析构构造函数c#析构构造函数c#析构构造函数
本文主要谈了 为什么构造函数不能是虚函数。
构造函数与默认构造函数的声明、定义、应用、比较
本程序包含构造函数和析构函数,可以把构造函数和析构函数的作用区分开
浅析构造函数不能为虚函数的理由,浅析构造函数不能为虚函数的理由,
构建一个类Point,它提供两个公有的构造函数,一个没有参数的Point构造函数和一个有两个double参数的构造函数。另外在该类中提供一个静态方法计算两个点的直线距离,传入参数为两个Point类实例。然后设计一个测试类...
C++ 拷贝构造函数 赋值构造函数 解释
C++\测试 对象成员构造函数、基类构造函数、派生类本身的构造函数 的先后顺序.rar
map使用std::map, CArray,int> > 错误, 解决: 重写CArray, 重载构造函数并加const 添加操作 operator =
C++ 默认构造函数C++ 默认构造函数C++ 默认构造函数C++ 默认构造函数C++ 默认构造函数C++ 默认构造函数C++ 默认构造函数C++ 默认构造函数C++ 默认构造函数C++ 默认构造函数C++ 默认构造函数C++ 默认构造函数
包含默认构造函数 初始化构造函数 复制构造函数 转换构造函数
C++中的构造函数、析构函数剖析 在C+ + 中, 构造函数是一个在构件对象的时 候调用的特殊的函数, 其目的是对对象进行初始 化工作, 从而使对象被使用之前可以处于一种合 理的状态。析构函数是在撤消对象时, 收回对象 ...
《Visual C++2012入门经典(第6版)》实例,在派生类的构造函数中调用基类的构造函数
4)构造函数的三个参数:小时、分、秒 设计为默认形成,其默认值为0。 5) 输出"构造函数被调用" 3、请设计一个拷贝构造函数,实现将参数的值全部传递给当前对象,同时输出“拷贝构造函数被调用” 4、请...
C++简单类的实现,包括构造函数,析构函数以及拷贝构造函数