• 禁用编译器自动生成的函数(Effective C++之06)


    如果想让你的类定义出来的对象是独一无二的,即对象无法被复制,或者使用赋值操作符赋给另外一个对象,那么最好的方法就是禁用拷贝构造函数和赋值操作符。下面介绍几种禁用的方法。(方法来自Effective C++,如果想禁用类的其他函数,方法类似)

    1. 定义为private且不实现它

    2. 继承Uncopyable类

    3. C++0x中的新方法


    1. 定义为private且不实现它

    我们知道,拷贝构造函数和赋值操作符重载函数,即使不定义,编译器也会生成一个默认的函数。但是如果定义了,class还是会支持这两个函数。那么应该怎么去禁用它们呢?

    在C++中,如果不想让对象调用某个方法,那么可以将这个方法声明为private,因此,我们可以将拷贝构造函数和赋值操作符重载函数声明为private,就可以阻止别人调用它了。但是,private函数还是可以在类的成员函数和friend函数中调用。这里还有一个技巧,就是将函数定义为private而且不实现它。

    class SpecialClass {
        ...
    private:
        SpecialClass(const SpecialClass&);
        SpecialClass& operator=(const SpecialClass&);    
    };

    将SpecialClass这样定义,并且不实现这两个函数,那么如果有人试图拷贝这个类的对象,编译器就会报错:

    SpecialClass sc1;
    SpecialClass sc2(sc1);        //error, 编译出错
    SpecialClass sc3;
    sc3 = sc1;                    //error, 编译出错

    而且即使在成员函数或者friend函数中调用了它,链接时也会出错

    2. 继承Uncopyable类

    第一种方法可以解决禁用拷贝构造函数的问题,但是还有一点不完美的是,如果用户不小心在成员函数或者friend函数中调用了它,那么这个错误只有到链接阶段才能被发现。所以就有了继承一个Uncopyable类的方法:

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

    此时,只需要继承Uncopyable类就可以防止其对象被拷贝了。其原理是:SpecialClass继承了Uncopyable函数,它的对象如果调用了拷贝构造函数,或者使用了赋值操作符,那么编译时,就会去调用基类的对应函数,但是基类里的这两个函数是private的,所以编译会失败。

    另外,boost也提供了一个Uncopyable函数,那个class名字为noncopyable,因此我们也可以这样做:

    #include <boost/utility.hpp>
    
    class SpecialClass : boost::noncopyable {
        ...
    };

    3. C++0x中的新方法

    在C++0x中,新添加了两个关键字:default和delete,可以用于控制某个类使用默认函数(default)或者禁用某个函数(delete)。其中,使用default关键字可以将某个函数定义为默认函数。如:

    class SpecialClass {
        ...
    public:
        SpecialClass(const SpecialClass&) = default;
        SpecialClass& operator=(const SpecialClass&) = default;    
    };

    可能这样写有点多余,但是它可以直观表示“我使用的默认的函数”。而且,如果有人想显式定义默认函数,但是自己写的代码又可能有错误,就可以使用这个关键字,方便且不出错。

    delete关键字可以禁用掉类的方法,正如我们上面前两节所做的事情,就可以用这一个关键字完成:

    class SpecialClass {
        ...
    public:
        SpecialClass(const SpecialClass&) = delete;        //禁用拷贝构造函数
        SpecialClass& operator=(const SpecialClass&) = delete;    
    };

    default关键字可以用于一切含有默认方法的函数。delete关键字可以用于类的所有方法,例如可以禁用掉函数的某些类型的参数:

    class SpecialClass {
        ...
    public:
        void fn(long);
        void fn(int) = delete;
    };
    
    SpecialClass sc;
    long l;
    sc.fn(l);        //ok, 调用void fn(long);
    int i;
    sc.fn(i);        //error, 调用void fn(int);

     上面的代码会将void fn(int)类型的函数禁用掉,而如果不禁用的话,sc.fn(i)会进行隐式转换调用void fn(long)函数。

     参考:

    C++11 FAQ

  • 相关阅读:
    c++中利用宏定义简化for循环使用
    UVA1152- 枚举 /二分查找
    acm 模板
    Xwindow的文章
    编程语言博客
    csh与bash比较
    关于锁与并发的资料总结
    linux su和sudo命令的区别
    对Memcached使用的总结和使用场景
    iptables配置——NAT地址转换
  • 原文地址:https://www.cnblogs.com/xiaoxinxd/p/effective_cpp_06.html
Copyright © 2020-2023  润新知