zoukankan      html  css  js  c++  java
  • C++35

    本文链接:https://blog.csdn.net/orange_littlegirl/article/details/101203278
                       
                   
                       
                   
                                                       
                
                
               
                                           
                       
                       
                                                文章目录32.在未来时态下发展程序33.将非尾端类(non-leaf classes)设计为抽象类(abstract classes)34.如何在同一个程序中结合 C++ 和 C35.让自己习惯于标准C++语言补充:auto_ptr实例代码
    系列文章:
    C++的35个技巧阅读笔记(一)
    C++的35个技巧阅读笔记(二)
    C++的35个技巧阅读笔记(三)
    C++的35个技巧阅读笔记(四)
    本次笔记为More Effective 35最后的杂项部分
    32.在未来时态下发展程序
    1、如果某个class在设计时,绝不打算成为derived classes(派生类),那么就不应该只是在头文件的class上端摆一样注释就好,而是应该以C++语法来阻止派生(见条款26)。
    2、如果要求其所有对象实体都必须于heap内产生,应该以条款27厉行这项约束。
    3、请为每一个class处理assignment 和copy constructor动作,即使没有人使用,现在没有不意味着将来没有。
    4、请努力让classes的操作符和函数拥有自然的语法和直观的语义。请和内建类型的行为保持一致:如有疑惑,请看ints有怎么样的表现。
    5、请让你的classes容易被正确地使用,不容易被误用,请接收“客户会犯错”的事实,并设计你的classes有预防、侦测或更正的能力。
    6、请努力写出可移植代码。
    7、请设计你的代码,使“系统改变所带来的冲击”得以局部化。尽可能采用封装性质,尽可能让实现细目成为private。尽量避免设计出virtual base classes,因为这种classes必须被其每一个derived class初始化。
    8、提供完整的classes——即使某些部分目前用不到。
    9、设计你的接口,使有利于共同的操作行为,阻止共同的错误。
    10、尽量使你的代码一般化(泛化),除非有不良的巨大后果。尽量用“未来式思维”去思考,它可增加你的代码重用性、加强其可维护性、使它更健壮,并促使在一个“改变实乃必然”的环境中有着优雅的改变。
    33.将非尾端类(non-leaf classes)设计为抽象类(abstract classes)
    允许通过指针进行“同型赋值”而阻止“异型赋值”的方法:
    1、通过两个赋值操作符重载,一个是virtual,一个是正常版本。该方法可以实现但是不推荐使用。
    2、让operator=成为Animal的private函数。
    class Animal
    {
    private:
    Animal& operatro=(const Animal& rhs);
    ...
    };
    class Lizard : public Animal {
    public:
    Lizard& operator=(const Lizard& rhs);
    ...
    };
    class Chicken : public Animal {
    public:
    Chicken& operator=(const Chicken& rhs);
    ...
    };
     
    Lizard liz1, liz2;
    ...
    liz1 = liz2;                //很好
    Chicken chick1, chick2;
    ...
    chick1 = chick2;            //很好
     
    Animal *pAnimal1 = &liz1;
    Animal *pAnimal2 = &chick1;
    ...
    *pAnimal1 = *pAnimal2;            //错误,企图调用private Animal::operator=
     
    不幸的是,Animal是一个具体类,而上述方法却使得Animal对象彼此间的赋值动作也不合法:
    Animal  animal1,animal2;
    animal1 = animal2;
    1234567891011121314151617181920212223242526272829303132
    正确的做法是:消除“允许Animal对象相互赋值”的需要,而完成此事的最简单做法是让Animal成为一个抽象类,Animal就无法被实例化。如果当初设计Animal要相互赋值,则改一个新的抽象类AbstractAnimal。
    class AbstractAnimal
    {
    protected:
        AbstractAnimal& operator=(const AbstractAnimal& rhs);
    public:
        virtual ~AbstractAnimal() = 0;        //它必须内含至少一个纯虚函数,一般让destructor成为纯虚函数
    ...
    };
    class Animal : public AbstractAnimal
    {
    public:
        Animal& operatro=(const Animal& rhs);
    ...
    };
    class Lizard : public AbstractAnimal {
    public:
        Lizard& operator=(const Lizard& rhs);
    ...
    };
    class Chicken : public AbstractAnimal {
    public:
        Chicken& operator=(const Chicken& rhs);
    ...
    };
    123456789101112131415161718192021222324
    将函数“声明为纯虚函数”并非暗示它没有实现码,而是意味着:
    1、目前这个class是抽象的。
    2、任何继承此class的具体类,都必须将纯虚函数重新声明为一个正常的虚函数(也就是说,不可以再令它 = 0)。
    如果是程序库中的具体类你要继承,( 从类库的实体类派生一个新类)有如下做法:
    1、将具体派生自既存的(程序库中的)具体类,但需要注意本条款一开始所验证的assignment相关问题,并且小心条款3所描述的数组相关陷阱。
    2、试着在程序库的继承体系中找到一个更高层的抽象类,其中你需要大部分功能,然后继承它。
    3、以“你所希望继承的那个程序库类”来实现你自己的新类,例如你可以令程序库类的一个对象成为你的data member,然后在你的新类中重新实现该程序库类的接口。
    4、使用类库的类,修改自己的程序增加非成员函数,不重写派生类。
    34.如何在同一个程序中结合 C++ 和 C
    1、name mangling(名称重整),C中你的函数名称不能重载。要压抑name mangling,必须使用C++的extern "C"指令:
    extern "C" {
    void drawLine(int x1, int y1);
    void simulate(int iterations);
    }
    1234
    2、Static 的初始化,一般在main函数最开始端插入一个static对象初始化构造操作,在最尾端安插一个static 对象的析构。
    3、动态内存分配,程序的C++部分使用new 和delete,程序的C部分使用malloc(及其变种)和free。
    4、数据结构的兼容性,将两个语言间的“数据结构传递”限制于C所能了解的形式;C++structs如果内含非虚函数,倒是不受此限。
    35.让自己习惯于标准C++语言

    在ARM(Annotated C++ Reference Manual)出版后的这些年,C++最重要的几项改变如下:
    1、增加了一些新的语言特性:RTTI、namespace、bool、关键词mutable 和explicit、enums最为重载函数之自变量所引发的类型晋升转换,以及在“class定义区内直接为整数型const static class members设定初值”的能力。
    2、扩充了Templates的弹性:允许member template存在、接纳“明白指示template当场实例化”的标准语法、允许function templates接受“非类型自变量”、可用class templates作为其他template的自变量。
    3、强化了异常处理机制:
    4、修改了内存分配历程:加入operator new[]和operator delete[],内存为分配成功时候抛出异常,在内存失败时返回0;
    5、增加了新的转型形式:static_cast,dynamic_cast,const_cast 和 reinterpret_cast.
    6、语言规则更为优雅精炼:重新定义虚函数时,其返回类型不再一定得与原定义完全吻合。

    STL标准程序库改变:
    1、支持C标准函数库。
    2、支持strings。
    3、支持本地化。
    4、支持I/O。
    5、支持数值应用。复数等
    6、支持广泛用途的container (容器)和 algorithm(算法)。

    补充:auto_ptr实例代码
    auto_ptr实例代码1
    template<class T>
    class auto_ptr {
    public:
        explict auto_ptr(T *p = 0);
        template<class U>
        auto_ptr(auto_ptr<U>& rhs);
     
        ~auto_ptr();
        template<class U>
        auto_ptr<T>& operator=(auto_ptr<U>& rhs);
        T& operator*() const;
        T* operator->() const;
        T* get() const;
        T* release();
     
        void reset(T *p = 0);
    private:
        T *pointee;
        template<class U>
        friend class auto_ptr<U>;
    };
     
    template<class T>
    template<class U>
        inline auto_ptr<T>::auto_ptr(auto_ptr<U>& rhs) : pointee(rhs.release()) {}
     
    template<class T>
        inline auto_ptr<T>::~auto_ptr() { delete pointee; }
     
    template<class T>
    template<class U>
        inline auto_ptr<T>& auto_ptr<T>::operator=(auto_ptr<T>& rhs)
        {
            if(this != &rhs) reset(rhs.release());
            return *this;
        }
     
    template<class T>
        inline T& auto_ptr<T>::operator*() const { return pointee; }
     
    template<class T>
        inline T* auto_ptr<T>::operator->() const { return pointee; }
     
    template<class T>
        inline T* auto_ptr<T>::get() const { return pointee; }
     
    template<class T>
        inline T* auto_ptr<T>::release()
        {
            T* oldPointee = pointee;
            pointee = 0;
            return oldPointee;
        }
     
    template<class T>
        inline void auto_ptr<T>::reset(T*p)
        {
            if(pointee != p) {
                delete pointee;
                pointee = p;
            }
        }
    1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
    auto_ptr实例代码2
    //所有函数都定义在class定义区内:
    template<class T>
    class auto_ptr {
    public:
        explicit auto_ptr(T *p = 0) : pointee(p) {}
     
    template<class U>
        auto_ptr(auto_ptr<U>& rhs) : pointee(rhs.release()) { }
        ~auto_ptr() { delete pointee: }
     
    template<class U>
        auto_ptr<T>& operator=(auto_ptr<U>& rhs)
        {
            if(this != &rhs) reset(rhs.release());
            return *this;
        }
     
        T& operator*() const { return *pointee; }
        T* operator->()const { return pointee; }
        T* get() cosnt { return pointee; }
        T* release()
        {
            T *oldPointee = pointee;
            pointee = 0;
            return oldPointee;
        }
     
        void reset(T *p = 0)
        {
            if(pointee != p) {
            delete pointee;
            pointee = p;
            }
        }
     
    private:
        T* pointee;
        template<class U> friend class auto_ptr<U>;
    };
    ————————————————
    版权声明:本文为CSDN博主「su扬帆启航」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/orange_littlegirl/article/details/101203278
  • 相关阅读:
    pygame中的图像和音乐
    pygame中鼠标画直线
    Python-GUI:button及entry的应用
    Linux查看物理CPU个数、核数、逻辑CPU个数
    阿里云nas使用记录
    字符集错误解决
    firewalld防火墙命令规则设置
    Linux之TCPIP内核参数
    nginx 301跳转https后post请求失效问题解决
    TCP queue 的一些问题
  • 原文地址:https://www.cnblogs.com/skydaddy/p/11928959.html
Copyright © 2011-2022 走看看