zoukankan      html  css  js  c++  java
  • Effective C++_笔记_条款12_复制对象时勿忘其每一个成分

    (整理自Effctive C++,转载请注明。整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 

        编译器会在必要时候为我们的classes创建copying函数,这些“编译器生成版”的行为:将被烤对象的所有成员变量都做一份拷贝。

        如果你声明自己的copying函数,意思就是告诉编译器你并不喜欢缺省实现中的某些行为。编译器仿佛被冒犯似的,会以一种奇怪的方式回敬:当你的实现代码几乎必然出错时却不告诉你。所以自己实现copying函数时,请遵循一条规则:如果你为class添加一个成员变量,你必须同时修改copying函数(你也需要修改class的所有构造函数以及任何非标准形式的operator=)。如果你忘记,编译器不太可能提醒你。

        但是也要注意,一旦发生继承,可能会造成此一主题最暗中肆虐的一个潜藏危机。试考虑:

       1: class PriorityCustomer:public Customer{
       2: public:
       3:     ...
       4:     PriorityCustomer( const PriorityCustomer& rhs) ;
       5:     PriorityCustomer& operator=( const PriorityCustomer& rhs ) ;
       6:     ...
       7: private:
       8:     int priority ;
       9: };
      10:  
      11: PriorityCustomer::PriorityCustomer( const PriorityCustomer& rhs )
      12:   :priority(rhs.priority)
      13: {
      14:     logCall("PriorityCustomer copy constructor" ) ;
      15: }
      16:  
      17: PriorityCustomer& PriorityCustomer::operator= ( const PriorityCustomer& rhs )
      18: {
      19:     logCall("PriorityCustomer copy assignment operator ");
      20:     priority = rhs.priority ;
      21:     return *this ;
      22: }

        我们可以看到,PriorityCustomer的copying函数看起来好像复制了PriorityCustomer的每一样东西。是的,它们复制了PriorityCustomer声明的成员变量,但每个PriorityCustomer还内含它所继承的Customer成员变量复件,而那些成员变量却未被复制。PriorityCustomer的copy构造函数并没有指定实参传给其base class构造函数,因此PriorityCustomer对象的Customer成分会被不带实参之Customer构造函数(即default构造函数---必定有一个否则无法通过编译)初始化。default构造函数对base class 成分执行缺省的初始化动作。

        以上事态在PriorityCustomer的copy assignment操作符身上只有轻微不同。它不曾企图修改其base class的成员变量,所以那些成员变量保持不变。

        任何时候只要你担负起“为derived class撰写copying函数”的重大责任,必须很小心地赋值其base class成分。那些成分往往是private,所以你无法直接访问它们,你应该让derived class的copying函数调用相应的base class函数:

       1: PriorityCustomer:PriorityCustomer( const PriorityCustomer& rhs )
       2:     :Customer(rhs),                //调用base class的copy构造函数
       3:      priority(rhs.priority)
       4: {
       5:     logCall( "PriorityCustomer copy constructor " ) ;
       6: }
       7:  
       8: PriorityCustomer&
       9: PriorityCustomer::operator=( const PriorityCustomer& rhs )
      10: {
      11:     logCall("PriorityCustomer copy assignment operator") ;
      12:     Customer::operator=(rhs) ;     //对base class成分进行赋值动作
      13:     priority = rhs.priority ;
      14:     return *this ;
      15: }

        本条款题目所说的“复制每一个成分”现在应该说的很清楚了。当你编写一个copying函数,请确保(1)复制所有local成员变量,(2)调用所有base class内适当的copying函数。

        另外,如果你发现你的copy构造函数和copy assignment操作符有相近的代码,消除重复代码的做法是,建立一个新的成员函数供两者调用。这样的函数往往是private且常被命名为init。这个策略可以安全消除copy构造函数和copy assignment操作符之间的代码重复。

        不要令某个copying函数调用另一个copying函数:令copy assignment操作符调用copy构造函数是不合理的,因为这试图构造一个已经存在的对象。反方向—令copy构造函数调用copy assignment操作符—同样无意义。构造函数用来初始化新对象,而assignment操作符只施行于已初始化对象身上。

        请记住:

    (1)Copying函数应该确保复制“对象内的所有的成员变量”及“所有base class成分”。

    (2)不要尝试以某个copying函数实现另一个copying函数。应该将共同机能放在第三个函数中,并有两个copying函数共同调用。

  • 相关阅读:
    Java 数组的浅拷贝和深拷贝
    Java 传递可变参数和方法重载
    Java 数组排序
    Java 一维数组作为参数和返回值
    Java 运算符及优先级
    MySQL 由 5.7 升级为 8.0 之后,Laravel 的配置改动
    Lavarel
    Laravel框架中Blade模板的用法
    php-fpm 配置文件检测
    Laravel Blade 模板 @section/endsection 与 @section/show, @yield 的区别
  • 原文地址:https://www.cnblogs.com/hust-ghtao/p/3814807.html
Copyright © 2011-2022 走看看