zoukankan      html  css  js  c++  java
  • C++学习笔记之编程思想

    编程思想

    单例(Singleton)模式

    实现思路:

    • Singleton拥有一个私有构造函数,确保用户无法通过new直接实例它;
    • 包含一个静态私有成员变量instance静态公有方法Instance()

    观察者(Observer)模式

    在观察者模式中,观察者需要直接订阅目标事件;在目标发出内容改变的事件后,直接接收事件并作出响应,对象常是一对多关系;

    观察者抽象类:

    #pragma once
    # ifndef OBSEVER_H_1
    # define OBSEVER_H_1
    class Observer
    {
    public:
        Observer() { ; }
        virtual ~Observer() { ; }
    
        // 当被观察对象发生变化时,通知被观察者调用这个方法
        virtual void Update(void* pArg) = 0;
    };
    # endif
    

    被观察者抽象类定义:

    #pragma once
    #include <string>
    #include <list>
    using namespace std;
    class Observerable
    {
    public:
        Observerable();
        virtual ~Observerable();
    
        // 注册观察者
        void Attach(Observer* pOb);
        // 反注册观察者
        void Detach(Observer* pOb);
    
        int GetObseverCount() const
        {
            return _Obs.size();
        }
    
        void DetachAll()
        {
            _Obs.clear();
        }
    
        virtual void GetSomeNews(string str)
        {
            SetChange(str);
        }
    protected:
        void  SetChange(string news);   // 有变化,需要通知
    
    private:
        void Notify(void* pArg);
    
    private:
        bool _bChange;
        list<Observer*> _Obs;
    };
    

    被观察者抽象类实现:

    #include "stdafx.h"
    #include "Observerable.h"
    #include "Observer.h"
    
    Observerable::Observerable():_bChange(false) { }
    
    Observerable::~Observerable(){ }
    
    // 注册观察者
    void Observerable::Attach(Observer* pOb)
    {
        if (pOb == NULL) { return; }
        // 看看当前列表中是否有这个观察者
        auto it = _Obs.begin();
        for (; it != _Obs.end(); it++)
        {
            if (*it == pOb)    { return; }
        }
        _Obs.push_back(pOb);
    }
    
    // 反注册观察者
    void Observerable::Detach(Observer* pOb)
    {
        if ((pOb == NULL) || (_Obs.empty() == true)) { return;     }
        _Obs.remove(pOb);
    }
    
    void Observerable::SetChange(string news)
    {
        _bChange = true;
        Notify( ( (void*)news.c_str() ));
    }
    
    void Observerable::Notify(void* pArg)
    {
        if (_bChange == false) { return; }
        // 看看当前列表中是否有这个观察者
        auto it = _Obs.begin();
        for (; it != _Obs.end(); it++)
        {
            (*it)->Update(pArg);
        }
        _bChange = false;
    }
    

    应用观察者模式:

    #include "stdafx.h"
    
    class News : public Observerable
    {
    public:
        virtual void GetSomeNews(string str)
        {
            SetChange("News: " + str);
        }
    };
    
    class User1:public Observer
    {
    public:
        virtual void Update(void* pArg)
        {
            cout << "User1 Got News: " << reinterpret_cast<char*>(pArg) <<endl;
        }
    };
    class User2 :public Observer
    {
    public:
        virtual void Update(void* pArg)
        {
            cout << "User2 Got News: " << reinterpret_cast<char*>(pArg) <<endl;
        }
    };
    
    int main()    
    {
        User1 u1;
        User2 u2;
    
        News n1;
        n1.GetSomeNews("T0");
        cout << n1.GetObseverCount() << endl;  // 0
    
        n1.Attach(&u1);
        n1.Attach(&u2);
        n1.GetSomeNews("T1");
        cout << n1.GetObseverCount() << endl;  // 2
    
        n1.Detach(&u2);
        n1.GetSomeNews("T2");
        cout << n1.GetObseverCount() << endl;  // 1
    
        n1.DetachAll();
        n1.GetSomeNews("T3");
        cout << n1.GetObseverCount() << endl;  // 0
    
        return 0;
    }
    

    void*、NULL和nullptr

    • 在C语言中:
    #define NULL ((void*)0)
    
    • 在C++语言中:
    #ifndef NULL
    #ifdef cplusplus
    #define NULL0
    #else
    #define NULL ((void*)0)
    #endif#endif
    
    • 在C++11中,nullptr用来替代(void*)0,NUL则只表示0
    #include <iostream>
    using namespace std;
    
    void func(void* i) { cout << "func(void* i)" << endl; }
    void func(int i) { cout << "func(int i)" << endl; }
    
    int main()
    {
        int* pi = NULL;
        int* pi2 = nullptr;
        char* pc = NULL;
        char* pc2 = nullptr;
        func(NULL);                   // func(int i)
        func(nullptr);                 // func(void* i)
        func(pi);                         // func(void* i)
        func(pi2);                       // func(void* i)
        func(pc);                        // func(void* i)
        func(pc2);                      // func(void* i)
        return 0;
    }
    

    C的类型转换

    • 隐式类型转换
    doublef=1.0/2;
    
    • 显式类型转换:(类型说明符)(表达式)
    double f=double(1)/double(2);
    

    C类型转换的问题:

    • 任意类型之间都可以转换,编译器无法判断其正确性
    • 难于定位:在源码中无法快速定位

    C++的类型转换

    • const cast:用于转换指针或引用,去掉类型的const属性(const变量即使内存被修改,读取的值不变,参考 const变量通过指针修改 详解 )。
    const int a = 10;
    //int* pA = &a;  //类型不一致错误
    int* pA = const_cast<int*>(&a);
    *pA = 100;
    cout << a;        //10,编译器只对const变量的值只读取一次
    
    • reinterpret_cast:重新解释类型(很危险),既不检查指向的内容,也不检查指针类型本身;但要求转换前后的类型所占用内存大小一致,否则将引发编译时错误。
    char* a = "a";
    void* b = a;
    char* c = reinterpret_cast<char*>(b);
    cout << c;      //a
    
    • static_cast:用于基本类型转换,有继承关系类对象和类指针之间转换,由程序员来确保转换是安全的,它不会产生动态转换的类型安全检查的开销。
    int i = 6;
    double d = static_cast<double>(i);     //基本类型转换  int -> double
    double d2 = 5.6;
    int i2 = static_cast<int>(d2);                //基本类型转换  double -> int
    cout << d  <<endl;   //6
    cout << i2 << endl;  //5
    
    • dynamic_cast:只能用于含有虚函数的类,必须用在多态体系中,用于类层次间的向上和向下转化;向下转化时,如果是非送的对于指针返回NULI。
    class Base
    {
    public:
        Base() : _i(0) { ; }
        virtual void T() { cout << "Base:T" << _i << endl; }
    private:
        int _i;
    };
    
    class Derived : public Base
    {
    public:
        Derived() :_j(1) { ; }
        virtual void T() { cout << "Derived:T" << _j << endl; }
    private: 
        int _j;
    };
    
    int main()
    {
        Base cb;
        Derived cd;
        Base* pcb;
        Derived* pcd;
    
        // 子类--》 父类
        pcb = static_cast<Base*>(&cd);
        if (pcb == NULL) { cout << "unsafe dynamic_cast from Derived to Base" << endl; }
        pcb = dynamic_cast<Base*>(&cd);
        if (pcb == NULL) { cout << "unsafe dynamic_cast from Derived to Base" << endl; }
        // 父类--》 子类
        pcd = static_cast<Derived*>(&cb);
        if (pcd == NULL)    { cout << "unsafe dynamic_cast from Derived to Base" << endl; }
        pcd = dynamic_cast<Derived*>(&cb);     //此处转换失败
        if (pcd== NULL)  { cout << "unsafe dynamic_cast from Derived to Base" << endl; }
        return 0;
    }
    

    适配器(Adapter)模式

    适配器模式的定义参考 设计模式 | 适配器模式及典型应用

    • 适配器将类接口转换为客户端期望的另一个接口;
    • 使用适配器可防止类由于接口不兼容而一起工作;
    • 适配器模式的动机是,如果可以更改接口,则可以重用现有软件;

    适配者类(被适配的角色,已存在的接口):

    class LegacyRectangle
    {
    public:
        LegacyRectangle(double x1, double y1, double x2, double y2)
        {
            _x1 = x1;
            _y1 = y1;
            _x2 = x2;
            _y2 = y2;
        }
    
        void LegacyDraw()
        {
            cout << "LegacyRectangle:: LegacyDraw()" << _x1 << " " << _y1 << " " << _x2 << " " << _y2 << endl;
        }
    
    private:
        double _x1;
        double _y1;
        double _x2;
        double _y2;
    };
    

    目标抽象类(客户所需接口):

    class Rectangle
    {
    public:
        virtual void Draw(string str) = 0;
    };
    

    第一种适配的方式——使用多重继承:

    class RectangleAdapter: public Rectangle, public LegacyRectangle
    {
    public:
        RectangleAdapter(double x, double y, double w, double h) :
            LegacyRectangle(x, y, x + w, y + h)
        {
            cout << "RectangleAdapter(int x, int y, int w, int h)" << endl;
        }
    
        virtual void Draw(string str)
        {
            cout << "RectangleAdapter::Draw()" << endl;
            LegacyDraw();
        }
    };
    

    第二种适配的方式——组合方式的Adapter:

    class RectangleAdapter2 :public Rectangle
    {
    public:
        RectangleAdapter2(double x, double y, double w, double h) :
            _lRect(x, y, x + w, y + h)
        {
            cout << "RectangleAdapter2(int x, int y, int w, int h)" << endl;
        }
    
        virtual void Draw(string str)
        {
            cout << "RectangleAdapter2::Draw()" << endl;
            _lRect.LegacyDraw();
        }
    private:
        LegacyRectangle _lRect;
    };
    

    使用适配器类:

    int main()
    {
        double x = 20.0, y = 50.0, w = 300.0, h = 200.0;
        RectangleAdapter ra(x, y, w, h);
        Rectangle* pR = &ra;
        pR->Draw("Testing Adapter");
    
        cout << endl;
        RectangleAdapter2 ra2(x, y, w, h);
        Rectangle* pR2 = &ra2;
        pR2->Draw("Testing2 Adapter");
    
        return 0;
    }
    

    结果:

    RectangleAdapter(int x, int y, int w, int h)
    RectangleAdapter::Draw()
    LegacyRectangle:: LegacyDraw()20 50 320 250
    
    RectangleAdapter2(int x, int y, int w, int h)
    RectangleAdapter2::Draw()
    LegacyRectangle:: LegacyDraw()20 50 320 250
    

    泛型编程的思想

    • 如果说面向对象是一种通过间接层来调用函数,以换取一种抽象,那么泛型编程则是更直接的抽象,它不会因为间接层而损失效率;

    • 不同于面向对象的动态期多态,泛型编程是一种静态期多态,通过编译器生成最直接的代码

    • 泛型编程可以将算法与特定类型、结构剥离,尽可能复用代码

    模板函数

    // 模板函数
    template<class T>
    T max(T a, T b)
    {
        return a > b ? a:b;
    }
    //特化
    template<>
    char* max(char* a, char* b)
    {
        return (strcmp(a, b) > 0 ?  (a) : (b));
    }
    template<class T1, class T2>
    int max(T1 a, T2 b)
    {
        return static_cast<int>(a > b ? a : b);
    }
    
    
    // 模板函数的测试
    cout << max(1, 2) << endl;
    cout << max(1.5, 3.5) << endl;
    cout << max('a', 'b') << endl;                  //b
    cout << max("hello", "world") << endl;   //hello
    
    char* s1 = "hello";
    char* s2 = "world";
    cout << max(s1, s2) << endl;             //world
    
    cout << max(10, 2.5) << endl;            //10
    

    模板类

    // 模板类
    template <class T>
    class TC
    {
    public:
        TC(T a, T b,  T c);
        T Min();
        T Max();
    
    private:
        T _a, _b, _c;
    };
    
    template<class T>
    TC<T>::TC(T a, T b, T c):_a(a), _b(b), _c(c) { ; }
    
    template<class T>
    T TC<T>::Min()
    {
        T minab = _a < _b ? _a : _b;
        return minab < _c ? minab : _c;
    }
    
    template<class T>
    T TC<T>::Max()
    {
        T maxab = _a < _b ? _b : _a;
        return maxab < _c ? _c : maxab;
    }
    
    // 模板类的测试
    TC<int> obj1(2, 4, 3);
    cout << obj1.Min() << endl;
    cout << obj1.Max() << endl;
    
    TC<double> obj2(2.5, 4.4, 3.3);
    cout << obj2.Min() << endl;
    cout << obj2.Max() << endl;
    
    TC<long> obj3(399950L, 455795L, 333339090L);
    cout << obj3.Min() << endl;
    cout << obj3.Max() << endl;
    

    泛型递归

    计算1+2+3...+100的值,使用泛型递归可以在编译期间计算出值:

    // 1+2+3...+100 ==> n*(n+1)/2 
    template<int n>
    struct Sum
    {
        enum Value {N = Sum<n-1>::N+n}; // Sum(n) = Sum(n-1)+n
    };
    template<>
    struct Sum<1>
    {
        enum Value {N = 1};    // n=1
    };
    
    int main()
    {
        cout << Sum<100>::N << endl;
        return 0;
    }
    
  • 相关阅读:
    Linux防火墙命令
    Linux学习笔记:(三)软件包管理(更新中)
    Linux赋予root权限
    Linux学习笔记:(二)用户和组群账户管理
    Linux目录结构
    Sublime Text3中Package Control Install Package打不开问题
    Linux学习笔记:(一)常用命令大全
    SpringBoot项目中整合Mybatis框架
    IDEA快速创建springboot项目
    java.lang.NoClassDefFoundError: javax/servlet/ServletOutputStream 报错解决
  • 原文地址:https://www.cnblogs.com/timefiles/p/CppStudyNotesProgrammingThought.html
Copyright © 2011-2022 走看看