编程学习biancheng.45soft.com 本站提供了各种在线教程和资料,供大家学习与参考.
编程学习
当前位置: 主页 > C++ > 复制控制 > C++ 复制控制 复制构造函数

C++ 复制控制 复制构造函数

只有单个形参,而且该形参是对本类类型对象的引用(常用 const 修饰),这样的构造函数称为复制构造函数。与默认构造函数一样,复制构造函数可由编译器隐式调用。复制构造函数可用于:

根据另一个同类型的对象显式或隐式初始化一个对象。

复制一个对象,将它作为实参传给一个函数。

从函数返回时复制一个对象。

初始化顺序容器中的元素。

根据元素初始化式列表初始化数组元素。



对象的定义形式

回忆一下,C++ 支持两种初始化形式(第 2.3.3 节):直接初始化和复制初始化。复制初始化使用 = 符号,而直接初始化将初始化式放在圆括号中。


当用于类类型对象时,初始化的复制形式和直接形式有所不同:直接初始化直接调用与实参匹配的构造函数,复制初始化总是调用复制构造函数。复制初始化首先使用指定构造函数创建一个临时对象(第 7.3.2 节),然后用复制构造函数将那个临时对象复制到正在创建的对象:

string null_book = "9-999-99999-9"; // copy-initialization
string dots(10, '.');               // direct-initialization

string empty_copy = string();       // copy-initialization
string empty_direct;                // direct-initialization

对于类类型对象,只有指定单个实参或显式创建一个临时对象用于复制时,才使用复制初始化。


创建 dots 时,调用参数为一个数量和一个字符的 string 构造函数并直接初始化 dots 的成员。创建 null_book 时,编译器首先调用接受一个 C 风格字符串形参的 string 构造函数,创建一个临时对象,然后,编译器使用 string 复制构造函数将 null_book 初始化为那个临时对象的副本。


empty_copy 和 empty_direct 的初始化都调用默认构造函数。对前者初始化时,默认构造函数函数创建一个临时对象,然后复制构造函数用该对象初始化 empty_copy。对后者初始化时,直接运行 empty_direct 的默认构造函数。


支持初始化的复制形式主要是为了与 C 的用法兼容。当情况许可时,可以允许编译器跳过复制构造函数直接创建对象,但编译器没有义务这样做。


通常直接初始化和复制初始化仅在低级别上存在差异。然而,对于不支持复制的类型,或者使用非 explicit 构造函数(第 12.4.4 节)的进修,它们有本质区别:

ifstream file1("filename"); // ok: direct initialization
ifstream file2 = "filename"; // error: copy constructor is private
// This initialization is okay only if
// the Sales_item(const string&) constructor is not explicit
Sales_item item = string("9-999-99999-9");

file1 的初始化是正确的。ifstream 类定义了一个可用 C 风格字符串调用的构造函数,使用该构造函数初始化 file1。


看上去等效的 file2 初始化使用复制初始化,但该定义不正确。由于不能复制 IO 类型的对象(第 8.1 节),所以不能对那些类型的对象使用复制初始化。


item 的初始化是否正确,取决于正在使用哪个版本的 Sales_item 类。某些版本将参数为一个 string 的构造函数定义为 explicit。如果构造函数是显式的,则初始化失败;如果构造函数不是显式的,则初始化成功。



形参与返回值

正如我们所知,当形参为非引用类型(第 7.2.1 节)的时候,将复制实参的值。类似地,以非引用类型作返回值时,将返回 return 语句 中的值的副本(第 7.3.2 节)。


当形参或返回值为类类型时,由复制构造函数进行复制。例如,考虑 第 7.3.2 节的 make_plural 函数:

// copy constructor used to copy the return value;
// parameters are references, so they aren't copied
string make_plural(size_t, const string&, const string&);

这个函数隐式使用 string 复制构造函数返回给定单词的复数形式。形参是 const 引用,不能复制。



初始化容器元素

复制构造函数可用于初始化顺序容器中的元素。例如,可以用表示容量的单个形参来初始化容器(第 3.3.1 节)。容器的这种构造方式使用默认构造函数和复制构造函数:

// default string constructor and five string copy constructors invoked
vector<string> svec(5);

编译器首先使用 string 默认构造函数创建一个临时值来初始化 svec,然后使用复制构造函数将临时值复制到 svec 的每个元素。


作为一般规则(第 9.1.1 节),除非你想使用容器元素的默认初始值,更有效的办法是,分配一个空容器并将已知元素的值加入容器。



构造函数与数组元素

如果没有为类类型数组提供元素初始化式,则将用默认构造函数初始化每个元素。然而,如果使用常规的花括号括住的数组初始化列表(第 4.1.1 节)来提供显式元素初始化式,则使用复制初始化来初始化每个元素。根据指定值创建适当类型的元素,然后用复制构造函数将该值复制到相应元素:

Sales_item primer_eds[] = { string("0-201-16487-6"),string("0-201-54848-8"),string("0-201-82470-1"),Sales_item()};

如前三个元素的初始化式中所示可以直接指定一个值,用于调用元素类型的单实参构造函数。如果希望不指定实参或指定多个实参,就需要使用完整的构造函数语法,正如最后一个元素的初始化那样。



13.1 练习题

什么是复制构造函数?何时使用它?

下面第二个初始化不能编译。可以从 vector 的定义得出什么推断?

vector<int> v1(42);  // ok: 42 elements, each 0
vector<int> v2 = 42; // error: what does this error tell us about vector?

假定 Point 为类类型,该类类型有一个复制构造函数,指出下面程序段中每一个使用了复制构造函数的地方:

Point global;

Point foo_bar(Point arg)
{
    Point local = arg;
    Point *heap = new Point(global);
    *heap = local;
    Point pa[ 4 ] = { local, *heap };
    return *heap;
}



编程学习 C++ 复制控制 复制构造函数 转载请保留此行.谢谢.

C++