在这里总结下C++类中的几个特殊成员函数

C++编译器会自动生成几个成员函数,这里属于接触到的新东西,而且如果不了解C++编译器的这种机制,在很多时候会因为隐式的调用这几个特殊的成员函数而导致程序发生错误。

特殊成员函数

  • 默认构造函数
  • 默认析构函数
  • 复制构造函数
  • 赋值运算符
  • 地址运算符

默认构造函数

因为创建类对象的时候总需要调用构造函数,若在类定义时候没有提供任何构造函数,C++将创建默认的构造函数。例如:

1
2
Klunk::Klunk()
{}

默认构造函数是Klunk类似于一个常规的自动变量,其中的值在初始化时是未知的。


复制构造函数

用于将一个对象复制到新创建的对象中。也就是说,他用于初始化过程中(包括在函数调用时按值传递参数,初始化形参的时候),而不是常规的赋值过程(赋值过程使用的是重载的赋值运算符)

原型:

1
Class_name(const Class_name &);

复制构造函数何时调用

  1. 在创建一个对象并且初始化为相同类型的对象的时候,复制函数都将被调用。例如下面这四种声明:

    1
    2
    3
    4
    5
    /*创建StringBad对象ditto并初始化为motto的副本*/
    StringBad ditto(motto);
    StringBad ditto = motto;
    StringBad ditto = StringBad(motto);
    StringBad * pStringBad = new StringBad(motto);
  2. 在函数中返回对象将调用对象的复制构造函数
    在函数返回对象(非引用)时,会调用对象的复制构造函数创建一个临时对象来表示返回值,后再使用这个临时对象(赋值,显示等等),在将其丢弃。

  3. 按值将对象传给函数的时候
    按值传递函数相当于将形参初始化为实参的值。

  4. 编译器生成临时对象

复制构造函数的功能

复制构造函数将逐个复制对象的非静态成员到调用对象中,如果是指针变量只复制指针的值,即所谓的浅复制。用代码表示:

1
StringBad sailor = sports;

等效于
1
2
3
StringBad sailor;
sailor.str = sports.str; // char指针变量
sailor.len = sports.len;

当然不能在程序中这么写啦,strlen这些都是sailor的私有变量。


赋值运算符

C++通过自动重载赋值运算符来允许类对象赋值。

赋值运算符重载何时使用

将已有的对象赋给另一个对象的时候,将使用重载的赋值运算符。例如

1
2
3
StringBad a = StringBad("shao");
StringBad b;
b = a;

赋值运算符的功能

也是类似复制构造函数,逐个将数据复制到调用对象中,静态变量不受影响
但在自定义赋值运算符的时候除了赋值数据还要:

  • 由于目标对象可能引用了以前分配的数据,所以在赋值前要使用delete将其释放
  • 避免将对象赋值给自身
  • 函数返回一个指向调用对象的引用,即返回*this

显式提供赋值运算符的步骤

  1. 判断是否是赋值给自身,例如

    1
    2
    if(this == &hs)
    return *this;
  2. 若是派生类的对象进行复制,先将基类的组件复制
    主要是通过作用域解析运算符显式的调用赋值运算符重载函数形式来赋值基类组件

    1
    baseDMA::operator=(hs);
  3. 删除就对象中的成员数据(通过new运算符动态分配的)

    1
    delete [] style;
  4. 将新的数据复制到调用的对象中

    1
    2
    style = new char[std::len(hs.style) + 1];
    std::strcpy(style, hs.style);
  5. 返回调用对象的引用(非const)

    1
    return *this;

地址运算符

隐式的地址运算符返回调用对象的地址(即this指针的值)

Comments