C++学习笔记之编程思想

x33g5p2x  于2022-02-11 转载在 C/C++  
字(8.1k)|赞(0)|评价(0)|浏览(311)

单例(Singleton)模式、观察者(Observer)模式、void*、NULL和nullptr、C的类型转换、C++的类型转换、适配器(Adapter)模式、泛型编程的思想

编程思想

单例(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 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;
}

相关文章