1.c++的构造函数有默认构造函数,一般的构造函数,赋值构造函数,拷贝构造函数(复制构造函数),强制类型转化构造函数。
2.如果没有定义构造函数和析构函数,则c++编译器会按照“位拷贝”的方式提供默认的构造函数(不初始化),默认的赋值构造函数(浅赋值),默认的拷贝构造函数(浅拷贝),默认的析构函数。位拷贝要小心指针,静态数据成员。
class String
{
public:
String(const char *str = NULL);
String(const String &other);
~String(void);
String & operator=(const String &other);
bool operator==(const String &str);
friend ostream & operator<<(ostream& o,const String &str);
private:
char *m_data;
};
3.例如如下的string类的两个对象stra和strb,stra =”windows”,strb = “linux”,如果没有进行深赋值,将strb赋值给stra即执行stra = strb,则stra.m_data和strb.m_data指向同一块内存区域,虽然stra.m_data的值变为linux,但这样会造成以下问题:
①stra.m_data原来指向的内存区域未被释放,会造成内存泄漏。
②stra.m_data和strb.m_data指向同一块内存区域,任何一方的改变都会影响另一方。
③当对象析构时strb.m_data所指向的区域会被释放两次(可能会造成悬挂指针)。
正确的拷贝构造函数书写如下:
String::String(const char *str)
{
if (str == NULL){
m_data = new char[1];
*m_data='\0';
}else{
int len=strlen(str) + 1;
m_data = new char[len];
strcpy_s(m_data,len,str);
}
}
/*析构函数*/
String::~String(void)
{
delete [] m_data;
}
String::String(const String &other)
{
int len = strlen(other.m_data) + 1;
m_data = new char[len];
strcpy(m_data,len,other.m_data);
}
/*赋值构造函数*/
String & String::operator=(const String &other)
{
/*防止自赋值,自赋值可能导致m_data指向一个不存在的对象,可能会出现 间接的自赋值*/
if (this == &other)
return *this;
/*防止内存泄漏*/
delete []m_data;
int len = strlen(other.m_data) + 1;
m_data = new char[len];
strcpy_s(m_data,len,other.m_data);
/*返回的是对象,而不是对象的地址,因为引用只是对象的别名*/
return *this;
}
/*判断是否相等*/
bool String::operator==(const String &str)
{
return strcmp(m_data,str.m_data) == 0;
}
ostream &String:: operator<<(ostream &o,const String &str)
{
o<<str.m_data;
return o;
}
4.拷贝构造函数的使用场景:
①对象以值传递的方式传入函数参数
void fun(String s){
}
fun(test);
test对象传入形参时,会产生一个临时变量,假设为s,然后调用拷贝构造函数把test拷贝给s,fun函数执行完后析构掉s.
②对象以值传递的方式从函数返回
string fun(){
string s("123");
return s;
}
执行过程:首先会产生一个临时变量就叫tmp,然后调用拷贝构造函数把s拷贝给tmp,然后fun程序结束后析构掉s,等到调用fun的函数结束后析构掉tmp.
③ 对象需要通过另外一个对象进行初始化;
string s(“123”);
string s1 = s;
string s2(s);
后两句都会调用拷贝构造函数。
通过声明一个私有拷贝构造函数,私有构造函数,私有赋值构造函数可以防止默认拷贝,默认构造,默认赋值构造发生。
5.拷贝构造函数形式
对于一个类X, 如果一个构造函数的第一个参数是下列之一:
a) X&
b) const X&
c) volatile X&
d) const volatile X&
且没有其他参数或其他参数都有默认值,那么这个函数是拷贝构造函数.类中可以存在超过一个拷贝构造函数,如果一个类中只存在一个参数为 X& 的拷贝构造函数,那么就不能使用const X或volatile X的对象实行拷贝初始化.如果一个类中没有定义拷贝构造函数,那么编译器会自动产生一个默认的拷贝构造函数。这个默认的参数可能为 X::X(const X&)或 X::X(X&),由编译器根据上下文决定选择哪一个。
赋值运算符和复制构造函数都是用已存在的B对象来创建另一个对象A。不同之处在于:赋值运算符处理两个已有对象,即赋值前B应该是存在的;复制构造函数是生成一个全新的对象,即调用复制构造函数之前A不存在。