默认样式:
className()
{
}//初始化值随机
//例如:
Klunk::Klunk()
{
klunk_ct=0;//可以用其设置特定的值
...
}
```c++
Klunk(int n=0)
{
klunk_ct=n;
}
```
- 只能有一个默认构造函数,否则会引发二义性
String::String()
{
len=0;
str=new char[l];//与下面析构函数相匹配
str[0]='\0';//default string
}
delete [] str;
delete[]与使⽤new[]初始化的指针和空指针都兼容。
String::String()
{
len=0;
//str=new char[l];//与下面析构函数相匹配
//str[0]='\0';
//更改为
str=0;
//default string
}
```c++
Class_name(const Class_name&);
```
它接受⼀个**指向类对象的常量引⽤**作为参数。
例如:StringBad(const StringBad&);
例子:
```c++
StringBad ditto(motto);
StringBad metto=motto;
StringBad also=StringBad(motto);
StringBad * pStringBad=new StringBad(motto);
```
- 其中中间的2种声明可能会使⽤复制构造函数直接创建metoo和 also,也可能使⽤复制构造函数⽣成⼀个临时对象,然后将临时对象的 内容赋给metoo和also,这取决于具体的实现。
- 最后⼀种声明使⽤motto **初始化⼀个匿名对象**,并将新对象的地址赋给pstring指针。
- 当函数**按值传递对象**(如程序清单12.3中的callme2())或**函数返回对象**时,都将使⽤复制构造函数。
- 按值传递意味着创建原始变量的⼀个副本。**编译器⽣成临时对象时,也将使⽤复制构造函数。**
```c++
StringBad::StringBad(const StringBad&)
{
num_strings++;
...
}
```
- 如果类中包含用于记录对象数的**静态成员**,且其值会在新对象被创建时发生变化,则应提供一个显式复制构造函数来处理计数问题。
- 隐式复制构造函数的功能相当于:
```c++
sailor.str=sport.str;
//复制的是指向字符串的指针,而不是字符串本身。
//当调用析构函数时将产生问题,可能对同一块内存区域进行两次删除,这将导致程序异常终止。
```
- 解决方案:定义一个显式复制构造函数。
- 解决类设计中这种问题的⽅法是进⾏深度复制(deep copy)。
- 复制构造函数应当复制字符串并将副本的地址赋给str成员,⽽不 仅仅是复制字符串地址。
函数实现:
```
StringBad::StringBad(const StringBad& st)
{
num_strings++;
len=st.len;
str=new char[len+1];
std::strcpy(str,st.str);
cout<<num_strings<<":\"<<str<<"\"object created"\n";
...
}
```
必须定义复制构造函数的原因在于,⼀些类成员是**使⽤new初始化**的、指向数据的指针,⽽不是数据本⾝。
- 如果类中包含了**使⽤new初始化的指针成员**,应当定义⼀个复制构造函数,**以复制指向的数 据,⽽不是指针**,这被称为深度复制。复制的另⼀种形式(成员复制或浅复制)只是复制指针 值。浅复制仅浅浅地复制指针信息,⽽不会深⼊“挖掘”以复制指针引⽤的结构。
ANSI C允许结构赋值,⽽C++允许类对象赋值,这是通过⾃动为类重载赋值运算符实现的。
```c++
Class_name & Class_name::operator=(const Class_name &);
//它接受并返回⼀个指向类对象的引⽤
//例子:
StringBad & StringBad::operator=(const StringBad &);
```
StringBad headline1("Celery Stalks at Midnight");
...
StringBad knot;
knot=headline1;
StringBad metoo=knot;
metoo是⼀个新创建的对象,被初始化为knot的值,因此使⽤复制构造函数。
实现时也可能分两步来处理这条语句:
使⽤复制构造函数创建⼀个临时对象,然后通过赋值将临时对象的值复制到新对象中。
初始化总是会调⽤复制构造函数, ⽽使⽤=运算符时也可能调⽤赋值运算符。
解决办法是提供赋值运算符(进⾏深度复制)定义。
S0=S1=S2;
//使用函数表示法时,转换为;
S0.operator=(S1.operator=(S2));
//,S1.operator=(S2)的返回值是函数S0.operator=()的参数。
//返回值是⼀个指向StringBad对象的引⽤,因此参数类型是正确的。
StringBad & StringBad::operator=(const StringBad & st)
{
if(this==&st)
return *this;
delete [] str;
len=st.len;
str=new char[len+1];
std::strcpy(str,st.str);
return *this;
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。