代码改变世界

boost noncopyable类

2015-02-03 10:47  youxin  阅读(1565)  评论(0编辑  收藏  举报

1. 当声明一个类时,编译器会自动为该类生成默认构造函数,复制构造函数,赋值操作符以及析构函数

2.自动生成的各个函数和操作符都是public的;

3.当声明一个类不允许复制时,可以将一个类的复制构造函数和赋值操作符声明为private,但是实际中,一般写一个noncopyable类,让不允许使用复制构造函数的类继承于该noncopyable类,boost类就实现了那么一个基类,代码很简单如下:

//  Boost noncopyable.hpp header file  --------------------------------------//

//  (C) Copyright Beman Dawes 1999-2003. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org/libs/utility for documentation.

#ifndef BOOST_CORE_NONCOPYABLE_HPP
#define BOOST_CORE_NONCOPYABLE_HPP

#include <boost/config.hpp>

namespace boost {

//  Private copy constructor and copy assignment ensure classes derived from
//  class noncopyable cannot be copied.

//  Contributed by Dave Abrahams

namespace noncopyable_  // protection from unintended ADL
{
  class noncopyable
  {
  protected:
#if !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) && !defined(BOOST_NO_CXX11_NON_PUBLIC_DEFAULTED_FUNCTIONS)
      BOOST_CONSTEXPR noncopyable() = default;
      ~noncopyable() = default;
#else
      noncopyable() {}
      ~noncopyable() {}
#endif
#if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS)
      noncopyable( const noncopyable& ) = delete;
      noncopyable& operator=( const noncopyable& ) = delete;
#else
  private:  // emphasize the following members are private
      noncopyable( const noncopyable& );
      noncopyable& operator=( const noncopyable& );
#endif
  };
}

typedef noncopyable_::noncopyable noncopyable;

} // namespace boost

#endif  // BOOST_CORE_NONCOPYABLE_HPP

 

模拟:

//
//  main.cpp
//  nocopy
//
//  Created by busyfisher on 13-6-17.
//  Copyright (c) 2013年 busyfisher. All rights reserved.
//

#include <iostream>
#include <string>

class nocopyable{
protected:
    nocopyable(){}
    ~nocopyable(){}
private:
    nocopyable(const nocopyable&);
    const nocopyable& operator =(const nocopyable&);
};

class person:public nocopyable{
public:
    person():age(0){}
    void set_name(const std::string& str){
        name = str;
    }
    void set_age(const int& _age){
        age = _age;
        
    }
private:
    int age;
    std::string name;
};

int main(){
    
    person p1;
    p1.set_age(20);
    p1.set_name("Liming");
    
    person p2(p1);<span style="font-family: Arial, Helvetica, sans-serif;">//错误,call to implicitly-deleted copy constructor of 'person'</span><span style="font-family: Arial, Helvetica, sans-serif;">}</span>

nocopyable.cpp: In copy constructor ‘Person::Person(const Person&)’:
nocopyable.cpp:10:2: error: ‘noncopyable::noncopyable(const noncopyable&)’ is private
noncopyable(const noncopyable&);
 上面继承不应该是Public,参考下面的:

一个疑惑:

noncopyable类中成员函数只有声明没有定义,行么?

Effective C++ 
item 06
“为了拒绝编译器自动提供的功能,将相应的函数声明为 private,而且不要给出实现”
网上有版本
C++箴言:拒绝不想用的编译器产生的函数
http://c.chinaitlab.com/cc/ccjq/200808/761013.html

刚试了一下

  1. class Test {
  2.           void print();
  3.           static void init();
  4. protected:
  5.        void test();
  6. public:
  7.            void print(int a) {
  8.                            cout << "Test" << endl;
  9.                            // init();      都不可访问, undefined reference 
  10.                            // print();
  11.                            // test();
  12.        }
  13.        // void p();    声明而不定义undefined reference
  14. };
复制代码


声明而不定义适用于private及protected的函数,但是public不行

用的Dev-C++,对它们(//注释行)的调用都是linker error,但是仅编译而不连接都可以通过
看来不管访问权限,声明而不定义对编译阶段没有影响,实际的检测是连接阶段

不知道总结得对不对。

C++箴言:拒绝不想用的编译器产生的函数

 
  如果你不想使用编译器为你产生的函数,就明确拒绝
 
  不动产代理商出售房屋,服务于这样的代理商的软件系统自然要有一个类来表示被出售的房屋:
 
  class HomeForSale { …… };
 
  每一个不动产代理商都会很快指出,每一件财产都是独特的——没有两件是完全一样的。在这种情况下,为 HomeForSale 对象做一个拷贝的想法就令人不解了。你怎么能拷贝一个独一无二的东西呢?最好让这种类似企图拷贝 HomeForSale 对象的行为不能通过编译:
 
 HomeForSale h1;
HomeForSale h2;
HomeForSale h3(h1); // attempt to copy h1 - should
// not compile!
h1 = h2; // attempt to copy h2 - should
// not compile!

  唉,防止这种编译的方法并非那么简单易懂。通常,如果你不希望一个 class 支持某种功能,你可以简单地不声明赋予它这种功能的函数。这个策略对于拷贝赋值运算符不起作用,因为,就象 Item 5 中指出的,如果你不声明它们,而有人又想调用它们,编译器就会隐式地声明它们。
 
  这就限制了你。如果你不声明拷贝构造函数和拷贝赋值运算符,编译器也可以为你生成它们。你的类还是会支持拷贝。另一方面,如果你声明了这些函数,你的类依然会支持拷贝。我们在这里的目标就是防止拷贝。 解决这个问题的关键是所有的编译器生成的函数都是 public.为了防止生成这些函数,你必须自己声明它们,但是你没有理由把它们声明为 public.相反,应该将拷贝构造函数和拷贝赋值运算符声明为 private.通过显式声明一个成员函数,可以防止编译器生成它自己的版本,而且将这个函数声明为 private,可以防止别人调用它。
 
  通常,这个方案并不十分保险,因为成员函数和友元函数还是能够调用 private 函数换句话说,除非你不定义它们。那么,当有人不小心地调用了它们,在连接的时候会出现错误。这个窍门——定义一个 private 成员函数却故意不去实现它——确实不错,在 C++ 的 iostreams 库里,就有几个类用此方法防止拷贝。比如,看一下你用的标准库的实现中,ios_base,basic_ios 和 sentry 的定义,你就会看到拷贝构造函数和拷贝赋值运算符被声明为 private 而且没有定义的情况。
 
  将这个窍门用到 HomeForSale 上,很简单:

 

 class HomeForSale {
 public:
  ..
 private:
  ...
  HomeForSale(const HomeForSale&); // declarations only
  HomeForSale& operator=(const HomeForSale&);
};

  你会注意到,我省略了函数参数的名字。这没有必要,只是一个普通的惯例。毕竟,函数不会被定义,极少有机会被用到,有什么必要指定参数的名字呢?
 
  对于上面的类定义,编译器将阻止客户拷贝 HomeForSale 对象的企图,如果你不小心在成员函数或者友元函数中这样做了,连接程序会提出抗议。
 
  将连接时错误提前到编译时间也是可行的(早发现错误毕竟比晚发现好),不要让 HomeForSale 自己去声明 private 的拷贝构造函数和拷贝赋值运算符,在一个特意设计的基类中声明。这个基类本身非常简单:

 

 class Uncopyable {
 protected: // allow construction
  Uncopyable() {} // and destruction of
  ~Uncopyable() {} // derived objects...
 private:
  Uncopyable(const Uncopyable&); // ...but prevent copying
  Uncopyable& operator=(const Uncopyable&);
};

  为了禁止拷贝 HomeForSale 对象,我们必须让它从 Uncopyable 继承:

 

 class HomeForSale: private Uncopyable { // class no longer
... // declares copy ctor or
}; // copy assign. operator

  在这里,如果有人——甚至是成员函数或友元函数——试图拷贝一个 HomeForSale 对象,编译器将试图生成一个拷贝构造函数和一个拷贝赋值运算符。就象 Item 12 解释的,这些函数的编译器生成版会试图调用基类的对应函数,而这些调用将被拒绝,因为在基类中,拷贝操作是 private 的。
 
  Uncopyable 的实现和使用包含一些微妙之处,比如,从 Uncopyable 继承不能是 public 的(参见 Item 32 和 39),而且 Uncopyable 的构造函数不必是 virtual 的(参见 Item 7)。因为 Uncopyable 不包含数据,所以它符合 Item 39 描述的空基类优化条件,但因为它是基类,此项技术的应用不能引入多重继承(参见 Item 40)。反过来说,多重继承有时会使空基类优化失效(还是参见 Item 39)。通常,你可以忽略这些微妙之处,而且此处只是用 Uncopyable 来做演示,因为它比较适合做广告。在 Boost(参见 Item 55)中你可以找到一个可用的版本。那个类名为 noncopyable.那是一个好的 class,我只是发现那个名字有一点儿不(un-)……嗯……非自然(nonnatural)。
 
  Things to Remember
 
  ·为了拒绝编译器自动提供的功能,将相应的函数声明为 private,而且不要给出实现。使用一个类似 Uncopyable 的基类是方法之一。
 
booost是Public:
class myclass: public boost::noncopyable  
{  
public:  
    myclass(){};  
    myclass(int i){};  
};  
  
int main()  
{  
    myclass cl1();  
    myclass cl2(1);  
  
    // myclass cl3(cl1);    // error  
    // myclass cl4(cl2);    // error  
  
    return 0;  
}