C++ Primer 学习笔记_54_类与数据抽象 --复制构造函数、赋值操作符(二)

2014-11-24 12:20:02 · 作者: · 浏览: 2
止任何复制类类型对象的尝试:用于代码中的复制尝试将在编译时标记为错误,而成员函数和友元中的复制尝试将在链接时导致错误!


大多数类应定义复制构造函数和默认构造函数

不定义复制构造函数和/或默认构造函数,会严重局限类的使用:不允许复制的类对象只能作为引用传递给函数或从函数返回,它们也不能用作容器的元素。

一般来说,最好显式或隐式定义默认构造函数和复制构造函数。只有不存在其他构造函数时才合成默认构造函数。如果定义了复制构造函数,也必须定义默认构造函数。


二、赋值操作符

与复制构造函数一样,如果类没有定义自己的赋值操作符,则编译器会合成一个!

1、介绍重载赋值

重载操作符是一些函数,其名字为operator后跟着所定义的操作符的符号。因此,通过定义名为operator=的函数,我们可以对赋值进行定义。像任何其他函数一样,操作符函数有一个返回值和一个形参表。形参表必须具有与该操作符数目相同的形参(如果操作符是一个类成员,则包括隐式this形参)。赋值是二元运算,所以该操作符函数有两个形参:第一个形参对应着左操作数,第二个形参对应右操作数。

大多数操作符可以定义为成员函数或非成员函数。当操作符为成员函数时,它的第一个操作数隐式绑定到this指针。有些操作符(包括赋值操作符)必须是定义自己的类的成员。因为赋值必须是类的成员,所以this绑定到指向左操作数的指针。因此,赋值操作符接受单个形参,且该形参是同一类类型的对象。右操作数一般作为const引用传递。

赋值操作符也返回对同一类类型的引用。

class Sales_item
{
public:
    Sales_item &operator=(const Sales_item &);
};

2、合成赋值操作符

合成赋值操作符会执行逐个成员赋值:右操作数对象的每个成员赋值给左操作数对象的对应成员。除数组之外,每个成员用所属类型的常规方式进行赋值。对于数组,给每个数组元素赋值。如:

Sales_item &Sales_item::operator=(const Sales_item &rhs)
{
    isbn = rhs.isbn;
    units_sold = rhs.units_sold;
    revenue = rhs.revenue;

    return *this;
}

3、复制和赋值常一起使用

实际上,应该将复制构造函数和赋值操作符看做一个单元,如果需要其中一个,我们几乎也可以肯定需要另一个!

//P412 习题13.9
NoName &NoName::operator=(const NoName &rhs)
{
    if (pstring)
    {
        delete pstring;
    }
    pstring = new string();
    *pstring = *(rhs.pstring);
    i = rhs.i;
    d = rhs.d;

    return *this;
}

//习题13.10
class Employee
{
public:
    typedef unsigned int num_type;

    Employee(const std::string Name = "NoName"):name(Name),mark(count)
    {
        set();
    }
    Employee(const Employee &rhs):name(rhs.name),mark(count)
    {
        set();
    }
    ~Employee()
    {
        -- count;
    }

    Employee &operator=(const Employee &rhs)
    {
        name = rhs.name;
        return *this;
    }

    ostream &output(ostream &os)
    {
        os << "Name: " << name << "\t\tMark: " << mark << endl;
        return os;
    }

private:
    std::string name;
    num_type mark;
    static num_type count;

    void set()
    {
        ++ count;
    }
};

Employee::num_type Employee::count = 0;