博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
高质量程序设计指南c++/c语言(35)--复制控制
阅读量:4611 次
发布时间:2019-06-09

本文共 4109 字,大约阅读时间需要 13 分钟。

      复制构造函数、赋值操作符和析构函数总称为复制控制(copy control),编译器会自动实现这些操作,但是类也可以定义自己的版本。通常,编译器合成的复制控制函数是非常精炼的--它们只做必须的工作。但对某些类而言,依赖于默认定义会导致灾难。实现复制控制操作最困难的部分,往往在于识别何时需要覆盖默认版本。有一种特别常见的情况需要类定义自己的复制控制函数,那就是类具有指针成员。

 1、复制构造函数

string null_book = "66666"; //首先调用一个接受c风格字符串形参的string构造函数,创建一个临时对象,然后,编译器使用string复制构造函数将null_book初始化为那个临时对象的副本。

ifstream file1("filename"); // ok:direct initilization

ifstream file2 = "filename"; // error:copy constructor is private

Sales_item item = string("3333"); //this initilization is ok only if the Sales_item(const string&) constructor is not explicit

1.1构造函数与数组元素

#include
using namespace std;class A{public: A() { data = 0; cout << "A()" << endl; } A(const A &a) { data = a.data; cout << "A(const A &a)" << endl; } A(int _data) { data = _data; cout << "A(int _data)" << endl; }private: int data;};int main(void){ A a[4] = {
1, 2, A(4)}; return 0;}

输出:

A(int _data)   //a[0]A(int _data)   //a[1]A(int _data)   //a[2]A(const A &a)  //a[2]A()            //a[3]

1.2初始化容器元素与构造函数

#include
#include
using namespace std;class A{public: A() { data = 0; cout << "A()" << endl; } A(const A &a) { data = a.data; cout << "A(const A &a)" << endl; }private: int data;};int main(void){ vector
b(4); //default A constructr and four copy constructrs are invoked
return 0; }

输出:

A()A(const A &a)A(const A &a)A(const A &a)A(const A &a)

 2、合成的赋值构造函数

      如果我们没有定义复制构造函数,编译器就会给我们合成一个。与合成的默认构造函数不同,即使我们定义了其他的构造函数,编译器也会合成复制构造函数。合成复制构造函数(synthesized copy constructor)的行为是,逐个成员初始化(memberwise initialize),将新对象初始化为原对象的副本。所谓“逐个成员”,指的是编译器将现有对象的每个非static成员,依次复制到正创建的对象。

     对许多类而言,合成复制构造函数只完成必要的工作。只包含类型成员或内置类型(但不是指针类型)成员的类,无需显示的定义复制构造函数。

3、禁止复制

     为了防止复制,类必须显示声明其复制构造函数为private。如果复制构造函数时私有的,则不允许用户代码复制该类类型的对象,编译器将拒绝任何进行复制尝试。 

    然而,类的友元和成员函数仍可进行复制。如下面:

#include
#include
using namespace std;class A{public: A() { data = 0; cout << "A()" << endl; } friend void f(const A &a);private: A(const A &a) { data = a.data; cout << "A(const A &a)" << endl; } int data;};void f(const A &a){ A b(a); //友元函数内仍然可以使用私有的复制构造函数 cout << a.data << endl;}int main(void){ A a; A b(a); //编译错误 return 0;}

如果想要连友元和成员中的复制也禁止,就可以声明一个private复制构造函数但不对其进行定义。声明而不定义成员函数是合法的,但是,使用未定义成员的任何尝试都将导致连接失败。通过声明但不定义private构造函数,可以禁止任何复制类类型对象的尝试:用户代码中的复制尝试将在编译时发生错误,而成员函数和友元中的复制尝试将在连接时出错。

4、赋值操作符

#include
#include
using namespace std;class A{public: A() { data = 0; cout << "A()" << endl; } A(int _data) { data = _data; cout << "A(int _data)" << endl; } A(const A &a) { data = a.data; cout << "A(const A &a)" << endl; } void print() { cout << "data:" << data << endl; }private: int data;};class B: public A{public: B(int data):A(data) { data1 = data; cout << "B(int data):A(data)" << endl; } B(const B &b) { data1 = b.data1; cout << "B(const B &b)" << endl; } void print() { A::print(); cout << "data1:" << data1 << endl; }private: int data1;};int main(void){ B b1(1); b1.print(); cout << endl; B b2(2); b2.print(); cout << endl; b1 = b2; b1.print(); cout << endl; return 0;}

输出:

A(int _data)B(int data):A(data)data:1data1:1A(int _data)B(int data):A(data)data:2data1:2data:2data1:2

即如果我们没有自定义赋值操作符,则编译器会为我们合成一个赋值操作符,它会把该类以及所有的父类的成员逐个复制。如果我们重写了子类的赋值操作符,但是在子类的赋值操作符内没有调用父类的赋值操作符的话,那么只会发生子类的成员赋值,父类的成员没有进行赋值。

void operator=(const B &b)    {        data1 = b.data1;        cout << "void operator=(const B &b)" << endl;    }//在子类B中加入赋值运算符重载函数,输出如下data:1data1:2

所以需要显示的调用父类的赋值运算符。

void operator=(const B &b)    {        A::operator=(b);        data1 = b.data1;        cout << "void operator=(const B &b)" << endl;    } //显示调用父类A的赋值运算符,输出如下: data:2 data1:2 至于父类A要不要重写赋值运算符,在本例中是无所谓的,因为如果我们不重写的话,编译器会自动合成一个。

 

转载于:https://www.cnblogs.com/zzj3/archive/2013/05/13/3076134.html

你可能感兴趣的文章
splay入门
查看>>
带CookieContainer进行post
查看>>
C语言学习笔记--字符串
查看>>
CSS-上下文选择器
查看>>
ionic repeat 重复最后一个时要执行某个函数
查看>>
1.初识代码审计-基础
查看>>
[Vue-rx] Stream an API using RxJS into a Vue.js Template
查看>>
解决VC几个编译问题的方法——好用
查看>>
SPOJ #11 Factorial
查看>>
City Upgrades
查看>>
“人少也能办大事”---K2 BPM老客户交流会
查看>>
关于七牛进行图片添加文字水印操作小计
查看>>
DataSource数据库的使用
查看>>
CentOS开启samba实现文件共享
查看>>
MSSQL使用sqlbulkcopy批量插入数据
查看>>
证明一个数能被3整除,当且仅当它的各位数的和能被3整除
查看>>
2018秋寒假作业4—PTA编程总结1
查看>>
android自适应屏幕
查看>>
2019-北航面向对象-电梯作业总结
查看>>
SqlHelper
查看>>