您的位置:首页 > 编程语言 > C语言/C++

C++常见知识点复习-赋值构造函数

2016-08-10 11:22 281 查看
(1) 一个空类或者空类对象的大小?

由于对象在内存中必须占有一定的空间,因此,即使类是空的,这个类的对象也要占用一定的空间。VS和G++中空类的大小都是1。

(2) 在空类中添加构造函数和析构函数,这个类对象的大小?

这里要明确的是:一个类对象在内存中包含哪些成员?在C++中,类对象中只有非静态的数据成员和虚表指针(如果有的话)。也就是说,虽然函数好像包含在对象中,但是,经过编译之后,类的函数就会编译成像C语言一样的全局函数,只是通过特定的对象进行调用。因此,在空类中添加函数并不会引起类对象大小的变化。

(3) 复制构造函数

书中给了下面这样的代码:

class A {
private:
int value;

public:
A(int n) { value = n; }
A(A other) { value = other.value; }

void Print() { std::cout << value << std::endl; }
};

int _tmain(int argc, _TCHAR* argv[])
{
A a = 10;
A b = a;
b.Print();

return 0;
}


我们必须知道的是,复制构造函数有三个场景下会被调用:
函数传递对象时;
函数返回对象时;
将一个对象赋给一个新的对象。 类A定义了复制构造函数,但是,其中的参数采用的是值传递。如果它是复制构造函数,主函数在调用A b = a;时,就会调用这个复制构造函数,但是,由于它采用值传递,那么还会调用复制构造函数,就产生了无限循环。因此,它是个错误的复制构造函数。编译这个程序时,G++会产生以下错误:
错误: 无效的构造函数:您要的可能是‘A (const A&)’


因此,复制构造函数的参数必须是const的引用,原因如下:
参数是const,可以从两方面来考虑,一方面,语义上,既然是复制构造函数,它不应该修改参数的值,因此,它应该是const;另一方面,如果不是const的话,上述代码中的A a = 10;就不能通过编译,因为这行代码会以这样的方式调用(这里有点问题,待查阅)。
参数是引用,防止产生无限循环,而且减少复制次数。


2
赋值运算符

为下面的CMyString添加赋值运算符函数。

class CMyString {
public:
CMyString(char *pData = NULL);
CMyString(const CMyString &str);
~CMyString(void);

private:
char *m_pData;
};


赋值运算符需要注意的问题是:
参数是const的引用。形参声明为const,是为了说明参数的常量性;形参说明为引用,可以减少调用复制构造函数的次数。
返回值是CMyString的引用,以允许连续赋值。
判断自身赋值。如果不判断自赋值,就直接进行赋值操作,有可能已经修改了实参的内容,赋值操作就无法完成。
对于像CMyString这样的管理动态存储空间的,在赋值时,还需要先释放原来的存储空间,再分配与实参一样的存储空间,最后将实参的内容拷贝进来。

因此,CMyString的赋值运算符函数如下:

CMyString& CMyString::operator=(const CMyString &str)
{
if(this == &str) { //判断自赋值
return *this;
}

delete [] m_pData; //释放原来的存储空间
m_pData = NULL;
m_pData = new char[strlen(str.m_pData) + ]; //分配跟参数一样多的存储空间,多申请一个字节是为了存储'0'
strcpy(m_pData, str.m_pData); //将参数的内容拷贝进来

return *this;
}



3
异常安全性。

那么,什么是异常安全性呢?

异常安全必须满足两个条件:
不泄漏任何资源;
不允许破坏数据。

如上的代码,如果在new char时,内存不足导致抛出异常,那么CMyString对象不再保有任何数据,如果对象出了作用域时,再次调用析构函数,就会发生未定义的错误。为了实现异常,主要的思路是,要使内存不足时,对象还是保持原来的状态。因此,书中给出的方法是,先用参数创建一个临时对象,将临时对象中的内容与对象进行交换,如果内存不足,就会在创建临时对象时失败,抛出异常,并没有修改对象的状态,而且,当临时对象出了作用域时,就会调用析构函数,释放对象原来的空间。可以看出,这里将释放原来的存储空间的操作和分配新存储空间的操作都交给了这个临时对象。

CMyString& CMyString::operator=(const CMyString &str)
{
if(this != &str) {
CMyString strTemp(str);

char *pTemp = strTemp.m_pData;
strTemp.m_pData = m_pData;
m_pData = pTemp;
}

return *this;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐