C++自带的古老的诅咒
话说,在大学刚接触C语言时,我们的老师便不断地!不断地!!不断地!!!告诉我们要把main函数分为5个部分:
1、声明+初始化 2、赋值 3、输入 4、输出 5、释放
我就非常不理解,为什么非要把『声明+初始化』以及『赋值』两步分开。
难道『初始化+赋值』一起会遭受诅咒?
明明教材就有程序是这么这样的:int i = 10; 更有甚者,直接int i, j = 1,k = 10; 连声明加赋值,直接都搞定。
而为什么老曹总逼我们把别人写一行的代码写成10行……
//initialization
int i = 0
int j = 0;
int k = 0;
//assignment
i = 0;
j = 1;
k = 10;
究竟是为什么需要将赋值这一步单独提出来呢?难道是由于这样做才能防止某种特殊的诅咒??对的!
我今天才发现其中包含了VC6.0包括VS2008中包含着这样一个“诅咒”~
首先我们写这样一段简单的代码
[cpp]
class Example
{
private:
int m_data1;
int m_data2;
int * m_pdata3;
public:
Example();
void setData(int given1, int given2, int given3);
};
Example::Example()
{
m_data1 = 0;
m_data2 = 0;
m_pdata3 = new int;
*m_pdata3 = 0;
}
void Example::setData(int given1, int given2, int given3)
{
m_data1 = given1;
m_data2 = given2;
*m_pdata3 = given3;
}
int _tmain(int argc, _TCHAR* argv[])
{
Example e1;
e1.setData(10, 20, 30);
Example e2;
e2 = e1; www.zzzyk.com
e2.setData(40, 50, 60);
return 0;
}
执行是可以通过的。
在这里,我们先定义Example类e1;后定义了Example类e2。我们并没有重载赋值运算符=,然而编译器却找到了一种方法使得 e2 = e1 这个运算符得以实现。那么,可以这么理解,在重载赋值 = 之前,系统默认创建了一个赋值函数。在这里,我们暂且把这个赋值函数叫做:默认赋值函数。
下面我们看一下默认赋值函数的功能。
首先,在e1.setData(10, 20, 30)后,监视到e1是这样的:
当e2 = e1 赋值后,e2的监视窗口如此:
可以看到,e1,e2中包含的指针m_pdata3指向同一片存储空间。如下的操作更能证明这点:
在e2.setData(40, 50, 60),对e2内部数据进行修改时,会发现e1内部指针对应的内存也进行了改变,变成了60
由此,我们可以推断,默认赋值函数的功能如下:将赋值符右边类的成员变量的取值原封不动得赋给左边的类内同样的成员变量。
既然清楚了,赋值运算符具有默认赋值函数。
下面我们手工给Example类重载赋值函数。
[cpp]
Example& Example::operator=(const Example& e)
{
m_data1 = e.m_data1;
m_data2 = e.m_data2;
m_pdata3 = new int;
*m_pdata3 = *(e.m_pdata3);
return *this;
}
当然,我们不希望改动e2指针内的数据,e1发生同样变化。换言之本类对象开辟的空间,归此类对象独有。因此,在重载时,开辟了空间后,将上一个空间中的值赋给新空间。
主函数不变:
[cpp]
int _tmain(int argc, _TCHAR* argv[])
{
Example e1;
e1.setData(10, 20, 30);
Example e2;
e2 = e1;
e2.setData(40, 50, 60);
return 0;
}
当执行完毕e2.setData(40, 50, 60)后,通过监视窗口,我们会发现:
果然,e2的开辟的空间变成了60,而e1没有变化。目的实现。
好了,有了这些储备,相信你会很容易理解这个“诅咒”了:
当你把刚刚主函数的两句
Example e2; //初始化
e2 = e1; //赋值
中的赋值与初始化合二为一,即写成Example e2 = e1后
主函数成为这样:
[cpp]
int _tmain(int argc, _TCHAR* argv[])
{
Example e1;
e1.setData(10, 20, 30);
Example e2 = e1;
e2.setData(40, 50, 60);
return 0;
}
让我们看看程序执行结果:
我们会发现,e2没有独立开辟空间,而是指向了e1的空间。
原来赋值与初始化合一时,调用的 = 运算符时,执行的不是重载的 = 运算符函数,而是默认赋值函数!
这就是那个将初始化与赋值合二为一的诅咒啊!不加区分也许有一天就会造成意想不到的问题!
补充:软件开发 , C++ ,