c++ 常用总结(三)

1.设计模式 

 GitHub - FengJungle/DesignPattern: Design pattern demo code

(一) 

① 简单工厂模式

 再不学简单工厂模式,就真的要去工厂搬砖啦~_冯Jungle的博客-CSDN博客

通过以下的例子可见,只需要提供产品名称作为参数,传入工厂的方法中,即可得到对应产品。抽象产品类中并没有提供公共方法的实现,而是在各个具体产品类中根据各自产品情况实现。

当然,简单工厂模式存在明显的不足。假设有一天Jungle想玩网球了,该怎么办呢?你肯定会说,这还不容易吗?再从抽象产品类派生出一个Tennis类,并在工厂类的getSportProduct方法中增加“productName == "Tennis”的条件分支即可。的确如此,但是这明显违背了开闭原则(对扩展开放,对修改关闭),即在扩展功能时修改了已有的代码。另一方面,简单工厂模式所有的判断逻辑都在工厂类中实现,一旦工厂类设计故障,则整个系统都受之影响!

例1

SimpleFactory.h

#ifndef _SIMPLE_FACTORY_
#define _SIMPLE_FACTORY_
 
#include <iostream>
 
// 抽象类
class AbstractSportProduct{
public:
    virtual void printName() = 0;
    virtual void play() = 0;
};
 
class Basketball : public AbstractSportProduct{
public:
    void printName(){std::cout << "Jungle get Basketball\n";}
    void play(){std::cout << "Jungle play Basketball\n";}
};
 
class Football : public AbstractSportProduct{
public:
    Football(){
		printName();
		play();
	}
    void printName(){std::cout << "Jungle get Football\n";}
    void play(){std::cout << "Jungle play Football\n";}
};
 
class Volleyball : public AbstractSportProduct{
public:
    void printName(){std::cout << "Jungle get Volleyball\n";}
    void play(){std::cout << "Jungle play Volleyball\n";}
};
 
class Factory{
public:
    std::shared_ptr<AbstractSportProduct> getSportProduct(std::string productName){
        std::shared_ptr<AbstractSportProduct> pro;
        if(productName == "Basketball"){
            pro = std::make_shared<Basketball>();
        }else if (productName == "Football"){
            pro = std::make_shared<Football>();
        }else if (productName == "Volleyball"){
            pro = std::make_shared<Volleyball>();
        }
        return pro;
    }
};
 
#endif

main.cpp

#include <iostream>
#include "SimpleFactory.h"
 
int main(){
    std::shared_ptr<Factory> f = std::make_shared<Factory>();
    std::shared_ptr<AbstractSportProduct> pro = f->getSportProduct("Basketball");
    pro->printName();
    pro->play();

    std::cout << "-------------------------\n";
    pro = f->getSportProduct("Football");

    std::cout << "-------------------------\n";
    pro = f->getSportProduct("Volleyball");
    pro->printName();
    pro->play();
 
    return 0;
}

② 工厂模式

如果Jungle想玩网球(Tennis),只需要增加一个棒球工厂(TennisFacory),然后在客户端代码中修改具体工厂类的类名,而原有的类的代码无需修改。由此可看到,相较简单工厂模式,工厂方法模式更加符合开闭原则。工厂方法是使用频率最高的设计模式之一,是很多开源框架和API类库的核心模式。

例1

FactoryMethod.h

#ifndef __FACTORY_METHOD__
#define __FACTORY_METHOD__
 
#include <iostream>
 
// 抽象产品类
class AbstractSportProduct{
public:
	virtual void printName() = 0;
	virtual void play() = 0;
};
 
class Basketball :public AbstractSportProduct{
public:
	void printName(){std::cout << "Jungle get Basketball\n";}
	void play(){std::cout << "Jungle play Basketball\n";}
};
 
class Football :public AbstractSportProduct{
public:
    Football(){
        printName();
        play();
    }
	void printName(){std::cout << "Jungle get Football\n";}
	void play(){std::cout << "Jungle play Football\n";}
};
 
class Volleyball :public AbstractSportProduct{
public:
	void printName(){std::cout << "Jungle get Volleyball\n";}
	void play(){std::cout << "Jungle play Volleyball\n";}
};
 
// 抽象工厂类
class AbstractFactory{
public:
    virtual std::shared_ptr<AbstractSportProduct> getSportProduct() = 0;
};
 
class BasketballFactory : public AbstractFactory{
public:
    std::shared_ptr<AbstractSportProduct> getSportProduct() {
        return std::make_shared<Basketball>();
    }
};
 
class FootballFactory : public AbstractFactory{
public:
    std::shared_ptr<AbstractSportProduct> getSportProduct() {
        return std::make_shared<Football>();
    }
};
 
class VolleyballFactory : public AbstractFactory{
public:
    std::shared_ptr<AbstractSportProduct> getSportProduct() {
        return std::make_shared<Volleyball>();
    }
};
 
#endif

main.cpp

#include <iostream>
#include "FactoryMethod.h"
 
int main(){
    std::shared_ptr<BasketballFactory> f = std::make_shared<BasketballFactory>();
    std::shared_ptr<AbstractSportProduct> pro = f->getSportProduct();
    pro->printName();
    pro->play();

    std::cout << "------------------------------\n";
    std::shared_ptr<FootballFactory> f1 = std::make_shared<FootballFactory>();
    pro = f1->getSportProduct();

    std::cout << "------------------------------\n";
    std::shared_ptr<VolleyballFactory> f2 = std::make_shared<VolleyballFactory>();
    pro = f2->getSportProduct();
    pro->printName();
    pro->play();
 
    return 0;
}

③ 抽象工厂模式

回顾之前的设计模式,简单工厂模式所有逻辑都封装在工厂类中,工厂根据客户提供的产品名字创建对应产品的对象实例;工厂方法模式将产品的创建过程放到了具体工厂类中,每一个工厂可以创建一个具体产品,由此可能会创建许多工厂类。很多时候,一个工厂不只是生产一种产品,而是生产一类产品,比如一个体育用品工厂,可以生产篮球、足球、排球等多种产品。此时我们可以把这些相关的产品归纳为一个“产品族”,由同一个工厂来生产,这即是Jungle今天要学习的抽象工厂模式。

例1

AbstractFactory.h

#ifndef __ABSTRACT_FACTORY__
#define __ABSTRACT_FACTORY__
 
#include <iostream>
 
// 抽象球类
class AbstractBall{
public:
    virtual void play() = 0;
};
 
class Basketball : public AbstractBall{
public:
    void play() {std::cout << "Jungle play Basketball\n";}
};
 
class Football : public AbstractBall{
public:
    void play() {std::cout << "Jungle play Football\n";}
};
 
// 抽象衬衫类
class AbstractShirt{
public:
    virtual void wearShirt() = 0;
};
 
class BasketballShirt : public AbstractShirt{
public:
    void wearShirt() {std::cout << "Jungle wear Basketball Shirt\n";}
};
 
class FootballShirt : public AbstractShirt{
public:
    void wearShirt() {std::cout << "Jungle wear Football Shirt\n";}
};
 
// 抽象工厂类
class AbstractFactory{
public:
    virtual std::shared_ptr<AbstractBall> getBall() = 0;
    virtual std::shared_ptr<AbstractShirt> getShirt() = 0;
};
 
class BasketballFactory : public AbstractFactory{
public:
    std::shared_ptr<AbstractBall> getBall(){
        std::cout << "Jungle get Basketball\n";
        return std::make_shared<Basketball>();
    }
    std::shared_ptr<AbstractShirt> getShirt(){
        std::cout << "Jungle get Basketball Shirt\n";
        return std::make_shared<BasketballShirt>();
    }
};
 
class FootballFactory : public AbstractFactory{
public:
    std::shared_ptr<AbstractBall> getBall(){
        std::cout << "Jungle get Football\n";
        return std::make_shared<Football>();
    }
    std::shared_ptr<AbstractShirt> getShirt(){
        std::cout << "Jungle get Football Shirt\n";
        return std::make_shared<FootballShirt>();
    }
};
 
#endif

main.cpp

#include <iostream>
#include "AbstractFactory.h"
 
int main(){
    std::shared_ptr<BasketballFactory> f = std::make_shared<BasketballFactory>();
    std::shared_ptr<AbstractBall> ab = f->getBall();    
    std::shared_ptr<AbstractShirt> as = f->getShirt();
    ab->play();
    as->wearShirt();

    std::cout << "---------------------------------\n";
    std::shared_ptr<FootballFactory> f1 = std::make_shared<FootballFactory>();
    ab = f1->getBall();    
    as = f1->getShirt();
    ab->play();
    as->wearShirt();
 
    return 0;
}

④ 建造者模式

例1

BuilderPattern.h

#ifndef __BUILDER_PATTERN__
#define __BUILDER_PATTERN__

#include <iostream>

// 产品类
class House{
public:
    void setFloor(std::string iFloor){
        this->floor = iFloor;
    }

    void setWall(std::string iWall){
        this->wall = iWall;
    }

    void setRoof(std::string iRoof){
        this->roof = iRoof;
    }

    void printfHouseInfo() {
        std::cout << "floor: " << floor << "\n";
        std::cout << "wall: "  << wall  << "\n";
        std::cout << "roof: "  << roof  << "\n";
    }

private:
    std::string floor;
    std::string wall;
    std::string roof;
};

// 抽象建造者
class AbstractBuilder{
public:
    AbstractBuilder(){house = std::make_shared<House>();}

    virtual void buildFloor() = 0;
    virtual void buildWall() = 0;
    virtual void buildRoof() = 0;
    virtual std::shared_ptr<House> getHouse() = 0;
    std::shared_ptr<House> house;
};

// 具体建造者A
class ConcreteBuilderA : public AbstractBuilder{
public:
    void buildFloor() {
        house->setFloor("Floor_A");
    }
    void buildWall(){
        house->setWall("Wall_A");
    }
    void buildRoof(){
        house->setRoof("Roof_A");
    }
    std::shared_ptr<House> getHouse(){
        return house;
    }
};

// 具体建造者B
class ConcreteBuilderB : public AbstractBuilder{
public:
    void buildFloor() {        
        house->setFloor("Floor_B");
    }
    void buildWall(){        
        house->setWall("Wall_B");
    }
    void buildRoof(){        
        house->setRoof("Roof_B");
    }
    std::shared_ptr<House> getHouse(){
        return house;
    }
};

// 指挥者
class Director{
public:
    void setBuilder(std::shared_ptr<AbstractBuilder> ibuilder){        
        builder = ibuilder;
    }
    // 封装组装流程,返回建造结果    
    std::shared_ptr<House> construct(){
        builder->buildFloor();
        builder->buildRoof();
        builder->buildWall();
        return builder->getHouse();
    }

private:    
    std::shared_ptr<AbstractBuilder> builder;
};

#endif

main.cpp

#include <iostream>
#include "BuilderPattern.h"

int main(){     
    // 指定具体建造者A  
    std::shared_ptr<Director> d = std::make_shared<Director>();
    std::shared_ptr<ConcreteBuilderA> cba = std::make_shared<ConcreteBuilderA>();
    d->setBuilder(cba);
    std::shared_ptr<House> h = d->construct();
    h->printfHouseInfo();

    std::cout << "---------------------------\n";
    // 指定具体建造者B
    std::shared_ptr<ConcreteBuilderB> cbb = std::make_shared<ConcreteBuilderB>();
    d->setBuilder(cbb);
    h = d->construct();
    h->printfHouseInfo();

    return 0;
}

⑤ 原型模式

原型模式通过复制一个已有对象来获取更多相同或者相似的对象。

例1

报错如下:Segmentation fault: 11 空指针问题

PrototypePattern.h

#ifndef __PROTOTYPE_PATTERN__
#define __PROTOTYPE_PATTERN__

#include <iostream>

class WorkModel{
public:
    void setWorkModelName(std::string imodelName){
        modelName = imodelName;
    }
    std::string getWorkModelName(){
        return modelName;
    }
private:
    std::string modelName;
};

class ConcreteWork {
public:
    std::shared_ptr<ConcreteWork> clone(){
        std::shared_ptr<ConcreteWork> cw = std::make_shared<ConcreteWork>();
        cw->setIdNum(idNum);
        cw->setIdName(idName);
        cw->setIWorkModel(iWorkModel);
        return cw;
    }
    std::shared_ptr<WorkModel> getIWorkModel(){
        return iWorkModel;
    }
    void setIdNum(int iIdNum){
        idNum = iIdNum;
    }
    void setIdName(std::string iIdName){
        idName = iIdName;
    }
    void setIWorkModel(std::shared_ptr<WorkModel> iIWorkModel){
        iWorkModel = iIWorkModel;
    }
    void printWorkInfo(){
        std::cout << "Name: " << idName << "\n";
        std::cout << "Num: "  << idNum  << "\n";
        std::cout << "ModelName: " << iWorkModel->getWorkModelName() << "\n";
    }

private:
    int idNum;
    std::string idName;
    std::shared_ptr<WorkModel> iWorkModel;
};

#endif

main.cpp 

#include <iostream>
#include "PrototypePattern.h"

int main(){
    std::shared_ptr<ConcreteWork> singleWork = std::make_shared<ConcreteWork>();
    singleWork->setIdNum(1001);
    singleWork->setIdName("single");
    std::shared_ptr<WorkModel> singleWorkModel = singleWork->getIWorkModel();
    // 错:singleWorkModel是空指针,执行setWorkModelName()会报错!
    singleWorkModel->setWorkModelName("single_model"); 
    std::cout << "single完成了作业:\n";

    return 0;
}

改正如下:

PrototypePattern.h

#ifndef __PROTOTYPE_PATTERN__
#define __PROTOTYPE_PATTERN__

#include <iostream>

class WorkModel{
public:
    void setWorkModelName(std::string imodelName){
        modelName = imodelName;
    }
    std::string getWorkModelName(){
        return modelName;
    }
private:
    std::string modelName;
};

class ConcreteWork {
public:
    std::shared_ptr<ConcreteWork> clone(){
        std::shared_ptr<ConcreteWork> cw = std::make_shared<ConcreteWork>();
        cw->setIdNum(idNum);
        cw->setIdName(idName);
        cw->setIWorkModel(iWorkModel);
        return cw;
    }
    void setIdNum(int iIdNum){
        idNum = iIdNum;
    }
    void setIdName(std::string iIdName){
        idName = iIdName;
    }
    void setIWorkModel(std::shared_ptr<WorkModel> iIWorkModel){
        iWorkModel = iIWorkModel;
    }
    void printWorkInfo(){
        std::cout << "Name: " << idName << "\n";
        std::cout << "Num: "  << idNum  << "\n";
        std::cout << "ModelName: " << iWorkModel->getWorkModelName() << "\n";
    }

private:
    int idNum;
    std::string idName;
    std::shared_ptr<WorkModel> iWorkModel;
};

#endif

main.cpp 

#include <iostream>
#include "PrototypePattern.h"

int main(){
    std::shared_ptr<ConcreteWork> singleWork = std::make_shared<ConcreteWork>();
    singleWork->setIdNum(1001);
    singleWork->setIdName("single");
    std::shared_ptr<WorkModel> workModel = std::make_shared<WorkModel>();
    workModel->setWorkModelName("single_model");
    singleWork->setIWorkModel(workModel);
    singleWork->printWorkInfo();

   std::shared_ptr<ConcreteWork> jungleWork = singleWork->clone();
   std::cout << "jungle正在抄作业...\n";

   std::cout << "jungle抄完了,正在改名字和学号,否则会被老师查出来...\n";
   jungleWork->setIdNum(1002);
   jungleWork->setIdName("jungle");
   workModel = std::make_shared<WorkModel>();
   workModel->setWorkModelName("jungle_Model");
   jungleWork->setIWorkModel(workModel);

   std::cout << "jungle也完成了作业:\n";
   jungleWork->printWorkInfo();

    return 0;
}

⑥ 单例模式

c++ 单例模式_乒乒乓乓丫的博客-CSDN博客

Singleton.h

#ifndef __SINGLETON_H__
#define __SINGLETON_H__

#include <iostream>
#include <mutex>

std::mutex m_mutex;

// 懒汉单例模式
class Singleton_Lazy{
public:
    static std::shared_ptr<Singleton_Lazy> getInstance(){
        std::cout << "singleton lazy mode.\n";
        if(instance == nullptr){
            m_mutex.lock();     // 加锁
            if(instance == nullptr){
                std::cout << "创建新的实例.\n";
                instance = std::make_shared<Singleton_Lazy>();
            }
            m_mutex.unlock();   // 解锁
        }
        return instance;
    }
    
private:
    static std::shared_ptr<Singleton_Lazy> instance;
};

std::shared_ptr<Singleton_Lazy> Singleton_Lazy::instance = nullptr;

// 饿汉单例模式
class Singleton_Hungry{
public:
    static std::shared_ptr<Singleton_Hungry> getInstance(){
        std::cout << "singleton hungry mode.\n";
        instance = std::make_shared<Singleton_Hungry>();
        return instance;
    }
private:
    static std::shared_ptr<Singleton_Hungry> instance;
};

std::shared_ptr<Singleton_Hungry> Singleton_Hungry::instance = nullptr;

#endif

main.cpp

#include <iostream>
#include "Singleton.h"
#include <pthread.h>

#define THREAD_NUM 6

void* callSingleton_Lazy(void*){
    std::shared_ptr<Singleton_Lazy> sl = Singleton_Lazy::getInstance();
    std::cout << "线程编号: " << pthread_self() << "\n";
}

void* callSingleton_Hungry(void*){
    std::shared_ptr<Singleton_Hungry> sh = Singleton_Hungry::getInstance();
    std::cout << "线程编号: " << pthread_self() << "\n";
}

int main(){
    pthread_t threads_pool[THREAD_NUM];
    int tids[THREAD_NUM];
    // 线程具有属性,用pthread_attr_t表示,在对该结构进行处理之前必须进行初始化,在使用后需要对其去除初始化。
    pthread_attr_t attr;
    void* status;

    // 创建 pthread_attr_t
    pthread_attr_init(&attr);       

    // 线程的分离状态决定一个线程以什么样的方式来终止自己。在默认情况下线程是非分离状态的,这种情况下,原有的线程等待创建的线程结束。
    // 只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。
    // PTHREAD _CREATE_JOINABLE(非分离线程)
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

    for(int i = 0; i < THREAD_NUM; i++){
        if(i < THREAD_NUM / 2){
            // 线程创建 pthread_create
            tids[i] = pthread_create(&threads_pool[i], nullptr, callSingleton_Lazy, (void*)&i);
        }else {
            std::cout << "-----------------\n";
            tids[i] = pthread_create(&threads_pool[i], nullptr, callSingleton_Hungry, (void*)&i);
        }
        if(tids[i]){
            std::cout << "Error: unable to create thread.\n";
            return 0;
        }
    }

    // 销毁 pthread_attr_t
    pthread_attr_destroy(&attr);    
    for(int i = 0; i < THREAD_NUM; i++){
        // pthread_join 主线程阻塞
        tids[i] = pthread_join(threads_pool[i], &status);
        if(tids[i]){
            std::cout << "Error: unable to join.\n";
            return 0;
        }
    }
    std::cout << "main exiting.\n";

    return 0;
}

⑦ 适配器模式

AdapterPattern.h

#ifndef __ADAPTERPATTERN_H__
#define __ADAPTERPATTERN_H__

#include <iostream>

// 适配者类DxfParser
class DxfParser{
public:
    void parseFile(){
        std::cout << "Parse dxf file\n";
    }
};

// 适配者类PathPlanner
class PathPlanner{
public:
    void calculate(){
        std::cout << "calculate path\n";
    }
};

class Adapter{
public:
    void pathPlanning(){
		std::cout << "pathPlanning\n";
        dxfParser->parseFile();
        pathPlanner->calculate();
	}
private:
    std::shared_ptr<DxfParser>   dxfParser;
    std::shared_ptr<PathPlanner> pathPlanner;
};

#endif

main.cpp 

#include <iostream>
#include "AdapterPattern.h"

int main(){
    std::shared_ptr<Adapter> adapter = std::make_shared<Adapter>();
    adapter->pathPlanning();

    return 0;
}

⑧  桥接模式

BridgePattern.h

#ifndef __BRIDGE_PATTERN_H__
#define __BRIDGE_PATTERN_H__

#include <iostream>

// 抽象类Game
class Game{
public:
    virtual void play() = 0;
};

class GameA : public Game {
public:
    void play(){
        std::cout << "Jungle玩游戏A\n";
    }
};

class GameB : public Game {
public:
    void play(){
        std::cout << "Jungle玩游戏B\n";
    }
};

// 抽象类Phone
class Phone{
public:
    virtual void setUpGame(std::shared_ptr<Game> igame) = 0;
    virtual void play() = 0;
private:
    std::shared_ptr<Game> game;
};

class PhoneA : public Phone{
public:
    void setUpGame(std::shared_ptr<Game> igame){
        game = igame;
    }
    void play(){
        game->play();
    }
private:
    std::shared_ptr<Game> game;
};

class PhoneB : public Phone{
public:
    void setUpGame(std::shared_ptr<Game> igame){
        game = igame;
    }
    void play(){
        game->play();
    }
private:
    std::shared_ptr<Game> game;
};

#endif

main.cpp

#include <iostream>
#include "BridgePattern.h"

int main(){
    // Jungle买了PhoneA品牌的手机,想玩游戏A
    std::shared_ptr<PhoneA> phoneA = std::make_shared<PhoneA>();
    std::shared_ptr<GameA> gameA = std::make_shared<GameA>();
    phoneA->setUpGame(gameA);
    phoneA->play();

    std::cout << "----------------\n";
    // Jungle想在这个手机上玩游戏B
    std::shared_ptr<GameB> gameB = std::make_shared<GameB>();
    phoneA->setUpGame(gameB);
    phoneA->play();

    return 0;
}

⑨  组合模式

  • 派生类中如果没有完全实现基类的所有纯虚函数,则此时的派生类也是抽象类,不能实例化对象。换言之,抽象类的派生类是允许不实现基类的所有纯虚函数的。

CompositePattern.h

#ifndef __COMPOSITE_PATTERN_H__
#define __COMPOSITE_PATTERN_H__

#include <iostream>
#include <vector>

// 抽象构件
class Component{
public:
    Component(){}
    Component(std::string iName){name = iName;}
    // 增加一个部门或办公室
	virtual void add(std::shared_ptr<Component> com) = 0;
    // 撤销一个部门或办公室
	virtual void remove(std::shared_ptr<Component> com) = 0;
    //
    virtual std::shared_ptr<Component> getChild(int num) = 0;
    // 各部门操作
    virtual void operation() = 0;
    std::string getName(){
        return name;
    }

private:
    std::string name;
};

// 叶子构件:办公室
// 没实现operation(),所以抽象类Component的子类Office也是抽象类,不能实例化!
class Office : public Component{
public:
    Office(){}
    Office(std::string iName){name = iName;}
    void add(std::shared_ptr<Component> com){
        std::cout << "not support!\n";
    }
    void remove(std::shared_ptr<Component> com){
        std::cout << "not support!\n";
    }
    std::shared_ptr<Component> getChild(int num){
        std::cout << "not support!\n";
        return nullptr;
    }    

private:
    std::string name;
};

// 叶子构件:行政办公室
// 虽然没实现add()、remove()、getChild(),但其基类Office已经实现过了这部分 ——>
// 所以派生类AdminOffice虽然只实现了operation(), 但其仍然可以实例化!
class AdminOffice : public Office{
public:
    AdminOffice(){}
    AdminOffice(std::string iName){name = iName;}    

    void operation(){
        std::cout << "-----Administration Office: " << name << "\n";
    }

private:
    std::string name;
};

// 叶子构件:教务办公室
// 可以实例化,原因同AdminOffice
class DeanOffice : public Office{
public:
    DeanOffice(){}
    DeanOffice(std::string iName){name = iName;}

    void operation(){
        std::cout << "-----Dean Office: " << name << "\n";
    }

private:
    std::string name;
};

// 容器构件SubComponent
// 实现了Component的所有纯虚函数,所以SubComponent可以实例化!
class SubComponent : public Component{
public:
    SubComponent(){}
    SubComponent(std::string iName){
        name = iName;
    }
    void add(std::shared_ptr<Component> com){
        componentList.push_back(com);
    } 
    void remove(std::shared_ptr<Component> com){
        for(int i = 0; i < componentList.size(); i++){
            // 遍历查找
            if(componentList[i]->getName() == com->getName()){
                componentList.erase(componentList.begin() + 1);
                break;
            }
        }
    }
    std::shared_ptr<Component> getChild(int num){
        return componentList[num];
    }
    void operation(){
        std::cout << name << "\n";
        for(int i = 0; i < componentList.size(); i++){
            componentList[i]->operation();
        }
    }

private:
    std::string name;
    // 构件列表
    std::vector<std::shared_ptr<Component> > componentList;
};

#endif

main.cpp

#include <iostream>
#include "CompositePattern.h"

int main(){
    std::shared_ptr<SubComponent> head   = std::make_shared<SubComponent>("总部");
    std::shared_ptr<SubComponent> sichuanBranch = std::make_shared<SubComponent>("四川分部");    
    std::shared_ptr<AdminOffice> office1 = std::make_shared<AdminOffice>("行政办公室");    
    std::shared_ptr<DeanOffice>  office2 = std::make_shared<DeanOffice>("教务办公室");    

    std::shared_ptr<SubComponent> cdBranch = std::make_shared<SubComponent>("成都分部");
    std::shared_ptr<SubComponent> myBranch = std::make_shared<SubComponent>("绵阳分部");    
    std::shared_ptr<AdminOffice> office3 = std::make_shared<AdminOffice>("行政办公室");    
    std::shared_ptr<DeanOffice>  office4 = std::make_shared<DeanOffice>("教务办公室"); 

    std::shared_ptr<AdminOffice> office5 = std::make_shared<AdminOffice>("行政办公室");    
    std::shared_ptr<DeanOffice>  office6 = std::make_shared<DeanOffice>("教务办公室"); 

    std::shared_ptr<AdminOffice> office7 = std::make_shared<AdminOffice>("行政办公室");    
    std::shared_ptr<DeanOffice>  office8 = std::make_shared<DeanOffice>("教务办公室"); 

    cdBranch->add(office5);
    cdBranch->add(office6);

    myBranch->add(office7);
    myBranch->add(office8);

    sichuanBranch->add(office3);
    sichuanBranch->add(office4);
    sichuanBranch->add(cdBranch);
    sichuanBranch->add(myBranch);

    head->add(office1);
    head->add(office2);    
    head->add(sichuanBranch);    

    head->operation();

    return 0;
}

⑩  装饰模式

DecoratorPattern.h

#ifndef __DECORATOR_PATTERN_H__
#define __DECORATOR_PATTERN_H__

#include <iostream>

// 抽象构件
class Component{
public:
	virtual void operation() = 0;
};

// 具体构件
class Phone : public Component{
public:
	void operation(){
		std::cout << "手机\n";
	}
};

class Decorator : public Component{
public:
    void operation(){
		component->operation();
	}
    void setComponent(std::shared_ptr<Component> iComponent){        
        component = iComponent;
    }
    std::shared_ptr<Component> getComponent(){
        return component;
    }

private:
    std::shared_ptr<Component> component;
};

// 具体装饰类:手机壳
class DecoratorShell : public Decorator{
public:
    void operation(){        
		getComponent()->operation();
        std::cout << "安装手机壳\n";
	}
};

// 具体装饰类:手机贴纸
class DecoratorSticker : public Decorator{
public:
    void operation(){        
		getComponent()->operation();
        std::cout << "贴卡通贴纸ֽ\n";
	}
};

//  具体装饰类:挂绳
class DecoratorRope : public Decorator{
public:
    void operation(){        
		getComponent()->operation();
        std::cout << "系手机挂绳\n";
	}
};

#endif

main.cpp

#include <iostream>
#include "DecoratorPattern.h"

int main(){
    std::cout << "Jungle's first phone\n";
    std::shared_ptr<Phone> p = std::make_shared<Phone>();    
    std::shared_ptr<DecoratorShell> ds = std::make_shared<DecoratorShell>();    
    ds->setComponent(p);
    ds->operation();

    std::cout << "\nJungle's second phone\n";
    std::shared_ptr<DecoratorSticker> dst = std::make_shared<DecoratorSticker>();   
    dst->setComponent(ds);
    dst->operation();

    std::cout << "\nJungle's third phone\n";
    std::shared_ptr<DecoratorRope> dr = std::make_shared<DecoratorRope>();   
    dr->setComponent(dst);
    dr->operation();

    return 0;
}

(二)

① 外观模式

FacadePattern.h

/*
 * @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @Date: 2021-08-19 11:19:57
 * @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @LastEditTime: 2023-03-13 10:29:14
 * @FilePath: /cpp_test/FacadePattern.h
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE#
 */
#ifndef __FACADE_PATTERN_H__
#define __FACADE_PATTERN_H__

#include <iostream>

class Memory{
public:
    void selfCheck(){
        std::cout << "memory selfchecking......\n";
    }
};

class Cpu{
public:
    void run(){
        std::cout << "running cpu......\n";
    }
};

class HardDisk{
public:
    void read(){
        std::cout << "reading hardDisk......\n";
    }
};

class Os{
public:
	void load(){
        std::cout << "loading os.....\n";		
	}
};

class Facade{
public:
    void powerOn(){
        std::cout << "power on……\n";	
        memory->selfCheck();
        cpu->run();
        hardDisk->read();
        os->load();        
        std::cout << "ready!\n";	        
    }

private:
    std::shared_ptr<Memory>   memory;
    std::shared_ptr<Cpu>      cpu;
    std::shared_ptr<HardDisk> hardDisk;
    std::shared_ptr<Os>       os;
};

#endif

main.cpp

#include <iostream>
#include "FacadePattern.h"

int main(){
    std::shared_ptr<Facade> f = std::make_shared<Facade>();
    f->powerOn();

    return 0;
}

② 享元模式

FlyweightPattern.h

/*
 * @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @Date: 2021-08-19 11:19:57
 * @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @LastEditTime: 2023-03-13 11:23:46
 * @FilePath: /cpp_test/FlyweightPattern.h
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#ifndef __FLYPATTERN_PATTERN_H__
#define __FLYPATTERN_PATTERN_H__

#include <iostream>
#include <vector>
#include <mutex>

std::mutex m_mutex;

// 抽象享元类
class NetDevice{
public:
    virtual std::string getName() = 0;
    void print(int portNum){
        std::cout << "NetDevice: " << getName() << ", port: " << portNum << "\n";
    }
};

// 具体享元类:集线器
class Hub : public NetDevice{
public:
    std::string getName(){
        return "集线器";
    }
};

// 具体享元类:交换机
class Switch : public NetDevice{
public:
    std::string getName(){
		return "交换机";
	}
};

// 享元工厂类
class NetDeviceFactory{
public:
    NetDeviceFactory(){
        std::shared_ptr<Hub> hub = std::make_shared<Hub>();        
        std::shared_ptr<Switch> switcher = std::make_shared<Switch>();        
        devicePool.push_back(hub);
        devicePool.push_back(switcher);
    }

    std::shared_ptr<NetDevice> getNetDevice(char c){        
        if(c == 'S'){
            return devicePool[1];
        }else if (c == 'H')
        {
            return devicePool[0];
        }else{
            std::cout << "wrong input!\n";
        }    
        return nullptr;    
    }

    // 单例模式:返回享元工厂类的唯一实例
    static std::shared_ptr<NetDeviceFactory> getFactory(){
        if(instance == nullptr){
            m_mutex.lock();
            if(instance == nullptr){
                instance = std::make_shared<NetDeviceFactory>();
            }
            m_mutex.unlock();
        }
        return instance;
    }

private:
    static std::shared_ptr<NetDeviceFactory> instance;
    // 共享池
    std::vector<std::shared_ptr<NetDevice> > devicePool;
};

std::shared_ptr<NetDeviceFactory> NetDeviceFactory::instance = nullptr;

#endif

main.cpp

#include <iostream>
#include "FlyweightPattern.h"

int main(){
    std::shared_ptr<NetDeviceFactory> netDeviceFactory = NetDeviceFactory::getFactory();

    // 客户端1获取一个hub
    std::shared_ptr<NetDevice> netDevice1 = netDeviceFactory->getNetDevice('H');
    netDevice1->print(1);
    // 客户端2获取一个hub
    std::shared_ptr<NetDevice> netDevice2 = netDeviceFactory->getNetDevice('H');
    netDevice2->print(2);
    std::cout << "判断两个hub是否是同一个:\n";
    std::cout << "netDevice1: " << netDevice1 << ", netDevice2: " << netDevice2 << "\n\n\n";

    // 客户端3获取一个switch
    std::shared_ptr<NetDevice> netDevice3 = netDeviceFactory->getNetDevice('S');
    netDevice3->print(1);
    // 客户端4获取一个switch
    std::shared_ptr<NetDevice> netDevice4 = netDeviceFactory->getNetDevice('S');
    netDevice4->print(2);
    std::cout << "判断两个switch是否是同一个:\n";
    std::cout << "netDevice3: " << netDevice3 << ", netDevice4: " << netDevice4 << "\n";

    return 0;
}

③ 代理模式

报错如下:

ProxyPattern.h

#ifndef __FLYPATTERN_PATTERN_H__
#define __FLYPATTERN_PATTERN_H__

#include <iostream>
#include "time.h"

// 抽象主题角色
class Subject{
public:
	virtual void method() = 0;
};

// 真实主题角色
class RealSubject : public Subject{
public:
	void method(){
        std::cout << "调用业务方法\n";		
	}
};

// Log类
class Log{
public:
	void getLog(){
		std::cout << "调用日志\n";
	}
};

// 代理类
class Proxy : public Subject{
public:
    void method(){
        log->getLog();
        realSubject->method();
        std::cout << "方法method()调用成功!\n";
	}

private:
    std::shared_ptr<RealSubject> realSubject;
    std::shared_ptr<Log> log;
};

#endif

main.cpp

#include <iostream>
#include "ProxyPattern.h"

int main(){
    std::shared_ptr<Proxy> p = std::make_shared<Proxy>();
    p->method();

    return 0;
}

修改如下:

ProxyPattern.h

#ifndef __FLYPATTERN_PATTERN_H__
#define __FLYPATTERN_PATTERN_H__

#include <iostream>
#include "time.h"

// 抽象主题角色
class Subject{
public:
	virtual void method() = 0;
};

// 真实主题角色
class RealSubject : public Subject{
public:
	void method(){
        std::cout << "调用业务方法\n";		
	}
};

// Log类
class Log{
public:
	void getLog(){
		std::cout << "调用日志\n";
	}
};

// 代理类
class Proxy : public Subject{
public:
    Proxy(){
        realSubject = std::make_shared<RealSubject>();
        log = std::make_shared<Log>();
    }

    void method(){
        log->getLog();
        realSubject->method();
        std::cout << "方法method()调用成功!\n";
	}

private:
    std::shared_ptr<RealSubject> realSubject;
    std::shared_ptr<Log> log;
};

#endif

也可修改如下:

ProxyPattern.h

#ifndef __FLYPATTERN_PATTERN_H__
#define __FLYPATTERN_PATTERN_H__

#include <iostream>
#include "time.h"

// 抽象主题角色
class Subject{
public:
	virtual void method() = 0;
};

// 真实主题角色
class RealSubject : public Subject{
public:
	void method(){
        std::cout << "调用业务方法\n";		
	}
};

// Log类
class Log{
public:
	void getLog(){
		std::cout << "调用日志\n";
	}
};

// 代理类
class Proxy : public Subject{
public:
    void method(){
        realSubject = std::make_shared<RealSubject>();
        log = std::make_shared<Log>();
        log->getLog();        
        realSubject->method();
        std::cout << "方法method()调用成功!\n";
	}

private:
    std::shared_ptr<RealSubject> realSubject;
    std::shared_ptr<Log> log;
};

#endif

④  职责链模式

ChainOfResponsibility.h

#ifndef __CHAIN_OF_RESPONSIBILITY_PATTERN_H__
#define __CHAIN_OF_RESPONSIBILITY_PATTERN_H__

#include <iostream>

// 请求:票据
class Bill{
public:
    Bill(){}
    Bill(int iId, std::string iName, double iAccount){
        id      = iId;
        name    = iName;
        account = iAccount;
    }

    void print(){
        std::cout << "id: " << id << "\n";
        std::cout << "name: " << name << "\n";
        std::cout << "account: " << account << "\n\n";
    }
    double getAccount(){
        return account;
    }

private:
    int         id;
	std::string name;
	double      account;
};

// 抽象处理者
class Approver{
public:
    // 添加上级
	void setSuperior(std::shared_ptr<Approver> iApprover){
        superior = iApprover;
    }
    // 处理请求
	virtual void handleRequest(std::shared_ptr<Bill> bill) = 0;

    std::shared_ptr<Approver> getSuperior(){
        return superior;
    }

    std::string getName(){
        return name;
    }

    void setName(std::string iName){
        name = iName;
    }

private:
    std::shared_ptr<Approver> superior;
    std::string name;
};

// 具体处理者:组长
class GroupLeader : public Approver{
public:
    GroupLeader(){}
    GroupLeader(std::string iName){
        setName(iName);
    }

    void handleRequest(std::shared_ptr<Bill> bill){
        if(bill->getAccount() < 10){
            std::cout << "组长: " << getName() << "处理了该票据,票据信息:\n";
            bill->print();
        }else{
            std::cout << "组长无权处理,转交上级……\n";
            getSuperior()->handleRequest(bill);
        }
    }
};

// 具体处理者:主管
class Head : public Approver{
public:
    Head(){}
    Head(std::string iName){
        setName(iName);
    }

    void handleRequest(std::shared_ptr<Bill> bill){
        if(bill->getAccount() >= 10 && bill->getAccount() < 30){
            std::cout << "主管: " << getName() << "处理了该票据,票据信息:\n";
            bill->print();
        }else{
            std::cout << "主管无权处理,转交上级……\n";
            getSuperior()->handleRequest(bill);
        }
    }
};

// 具体处理者:经理
class Manager : public Approver{
public:
    Manager(){}
    Manager(std::string iName){
        setName(iName);
    }

    void handleRequest(std::shared_ptr<Bill> bill){
        if(bill->getAccount() >= 30 && bill->getAccount() < 60){
            std::cout << "经理: " << getName() << "处理了该票据,票据信息:\n";
            bill->print();
        }else{
            std::cout << "经理无权处理,转交上级……\n";
            getSuperior()->handleRequest(bill);
        }
    }
};

// 具体处理者:老板
class Boss : public Approver{
public:
    Boss(){}
    Boss(std::string iName){
        setName(iName);
    }

    void handleRequest(std::shared_ptr<Bill> bill){
        std::cout << "老板: " << getName() << "处理了该票据,票据信息:\n";
        bill->print();
    }
};

#endif

main.cpp

#include <iostream>
#include "ChainOfResponsibility.h"

int main(){
    std::shared_ptr<GroupLeader> groupLeader = std::make_shared<GroupLeader>("孙组长");
    std::shared_ptr<Head> head = std::make_shared<Head>("兵主管");
    std::shared_ptr<Manager> manager = std::make_shared<Manager>("春经理");
    std::shared_ptr<Boss> boss = std::make_shared<Boss>("孙老板");

    // 添加上级
    groupLeader->setSuperior(head);
    head->setSuperior(manager);
    manager->setSuperior(boss);

    // 创建报销单
    std::shared_ptr<Bill> bill1 = std::make_shared<Bill>(1, "Jungle", 8);
    std::shared_ptr<Bill> bill2 = std::make_shared<Bill>(2, "Lucy", 14.4);
    std::shared_ptr<Bill> bill3 = std::make_shared<Bill>(3, "Jack", 32.9);
    std::shared_ptr<Bill> bill4 = std::make_shared<Bill>(4, "Tom", 89);

    // 全部先交给组长审批
    groupLeader->handleRequest(bill1);
    groupLeader->handleRequest(bill2);
    groupLeader->handleRequest(bill3);
    groupLeader->handleRequest(bill4);

    return 0;
}

⑤  命令模式

CommandPattern.h

#ifndef __COMMAND_PATTERN_H__
#define __COMMAND_PATTERN_H__

#include <iostream>
#include <vector>

// 命令队列类
#define COMMAND_QUEUE

// 抽象命令类 
class Command{
public:
	virtual void execute() = 0;
};

// 接收者:电灯类
class Lamp{
public:
    void on(){
		lampState = true;
		std::cout << "Lamp is on\n";
	}
    void off(){
		lampState = false;
		std::cout << "Lamp is off\n";
	}
    bool getLampState(){
        return lampState;
    }

private:
    bool lampState;
};

// 接收者:风扇类
class Fan{
public:
    void on(){
		fanState = true;
		std::cout << "Fan is on\n";
	}
    void off(){
		fanState = false;
		std::cout << "Fan is off\n";
	}
    bool getFanState(){
        return fanState;
    }

private:
    bool fanState;
};

// 具体命令类 LampCommand
class LampCommand : public Command{
public:
    LampCommand(){
        lamp = std::make_shared<Lamp>();
    }
    void execute(){
        if(lamp->getLampState()){
            lamp->off();
        }else{
            lamp->on();
        }
    }

private:
    std::shared_ptr<Lamp> lamp;
};

// 具体命令类 FanCommand
class FanCommand : public Command{
public:
    FanCommand(){
        fan = std::make_shared<Fan>();
    }
    void execute(){
        if(fan->getFanState()){
            fan->off();
        }else{
            fan->on();
        }
    }

private:
    std::shared_ptr<Fan> fan;
};

// 调用者 Button
class Button{
public:    
    void setCommand(std::shared_ptr<Command> iCom){
        command = iCom;
    }
    void touch(){
        std::cout << "触摸开关:\n";
        command->execute();
    }

private:
    std::shared_ptr<Command> command;
};

#ifdef COMMAND_QUEUE

// 命令队列类
class CommandQueue{
public:
    void addCommand(std::shared_ptr<Command> com){
        commandQueue.push_back(com);
    }
    void execute(){
        for(int i = 0; i < commandQueue.size(); i++){
            commandQueue[i]->execute();
        }
    }

private:
    std::vector<std::shared_ptr<Command> > commandQueue;
};

// 调用者 Button2
class Button2{
public:
    void setCommandQueue(std::shared_ptr<CommandQueue> iCommandQueue){
        commandQueue = iCommandQueue;
    }
    void touch(){
        std::cout << "触摸开关:\n";
        commandQueue->execute();
    }

private:
    std::shared_ptr<CommandQueue> commandQueue;
};

#endif

#endif

main.cpp

#include <iostream>
#include "CommandPattern.h"

int main(){
    // 按钮
    std::shared_ptr<Button> bt = std::make_shared<Button>();
    // 按钮控制电灯
    std::shared_ptr<LampCommand> lc = std::make_shared<LampCommand>();
    bt->setCommand(lc);
    bt->touch();
    bt->touch();
    bt->touch();
    bt->touch();
    std::cout << "\n\n";

    std::shared_ptr<FanCommand> fc = std::make_shared<FanCommand>();
    bt->setCommand(fc);
    bt->touch();
    bt->touch();
    bt->touch();
    bt->touch();
    std::cout << "-------------------------\n";

#ifdef COMMAND_QUEUE
    std::shared_ptr<Button2> bt2 = std::make_shared<Button2>();    
    std::shared_ptr<CommandQueue> cq = std::make_shared<CommandQueue>();       
    cq->addCommand(lc);
    cq->addCommand(fc);
    bt2->setCommandQueue(cq);
    bt2->touch();

#endif
    return 0;
}

⑥ 备忘录模式

Memento.h

#ifndef __MEMENTO_H__
#define __MEMENTO_H__

#include <iostream>

class Memento{
public:
    Memento(){}
    Memento(int iVersion, std::string iDate, std::string iLabel){
        version = iVersion;
        date    = iDate;
        label   = iLabel;
    }
    int getVersion(){
        return version;
    }
    std::string getDate(){
        return date;
    }
    std::string getLabel(){
        return label;
    }

private:
    int         version;
	std::string date;
	std::string label;
};

#endif

Originator.h

#ifndef __CODEVERSION_H__
#define __CODEVERSION_H__

#include <iostream>
#include "Memento.h"

class CodeVersion{
public:
    CodeVersion(){
		version = 0;
		date    = "1900-01-01";
		label   = "none";
	}
	CodeVersion(int iVersion, std::string iDate, std::string iLabel){
		version = iVersion;
		date    = iDate;
		label   = iLabel;
	}
    std::shared_ptr<Memento> save(){
        return std::make_shared<Memento>(version, date, label);
    }
    std::shared_ptr<Memento> commit(){
        return std::make_shared<Memento>(version, date, label);
    }
    void restore(std::shared_ptr<Memento> mem){
        version = mem->getVersion();
        date    = mem->getDate();
        label   = mem->getLabel();
    }

private:
    int         version;
	std::string date;
	std::string label;
};

#endif

CodeManager.h 

#ifndef __CODEMANAGER_H__
#define __CODEMANAGER_H__

#include <iostream>
#include <vector>
#include "Memento.h"

class CodeManager{
public:
    void commit(std::shared_ptr<Memento> mem){
        std::cout << "version: " << mem->getVersion() << 
        ", date: " << mem->getDate() << ", label: " << mem->getLabel() << "\n";
        mementoList.push_back(mem);
    }
    std::shared_ptr<Memento> switchToPointedVersion(int index){
        mementoList.erase(mementoList.begin() + mementoList.size() - index, mementoList.end());
        return mementoList[mementoList.size() - 1];
    }
    void codeLog(){
        for (int i = 0; i < mementoList.size(); i++){
            std::cout << "version: " << mementoList[i]->getVersion() << 
            ", date: " << mementoList[i]->getDate() << ", label: " << mementoList[i]->getLabel() << "\n";
        }
    }

private:
    std::vector<std::shared_ptr<Memento> > mementoList;
};

#endif

main.cpp

#include <iostream>
#include "Originator.h"
#include "CodeManager.h"

int main(){    
    std::shared_ptr<CodeManager> Jungle  = std::make_shared<CodeManager>();    
    std::shared_ptr<CodeVersion> codeVer = std::make_shared<CodeVersion>(1001, "2019-11-03", "Initial version");  

    std::cout << "提交初始版本:\n";
    Jungle->commit(codeVer->save());  

    std::cout << "\n提交一个版本,增加了日志功能:\n";
    codeVer = std::make_shared<CodeVersion>(1002, "2019-11-04", "Add log funciton"); 
    Jungle->commit(codeVer->save());  

    std::cout << "\n提交一个版本,增加了Qt图片浏览器:\n";
    codeVer = std::make_shared<CodeVersion>(1003, "2019-11-05", "Add Qt Image Browser"); 
    Jungle->commit(codeVer->save());  

    std::cout << "\n查看提交历史\n";
    Jungle->codeLog();

    std::cout << "\n回退到上一个版本\n";
    codeVer->restore(Jungle->switchToPointedVersion(1));

    std::cout << "\n查看提交历史\n";
    Jungle->codeLog();

    return 0;
}

⑦ 策略模式

Strategy.h

#ifndef __STRATEGY_H__
#define __STRATEGY_H__

#include <iostream>

// 抽象策略类
class Strategy{
public:
    virtual void sort(int arr[], int N) = 0;
};

// 具体策略:冒泡排序
class BubbleSort : public Strategy{
public:
    BubbleSort(){
		std::cout << "冒泡排序\n";
	}
    void sort(int arr[], int N){
		for (int i = 0; i<N; i++)
		{
			for (int j = 0; j<N - i - 1; j++)
			{
				if (arr[j]>arr[j + 1]){
					int tmp = arr[j];
					arr[j] = arr[j + 1];
					arr[j + 1] = tmp;
				}
			}
		}
	}
};

// 具体策略:选择排序
class SelectionSort : public Strategy{
public:
    SelectionSort(){
		std::cout << "选择排序\n";
	}
    void sort(int arr[], int N){
		int i, j, k;
		for (i = 0; i<N; i++)
		{
			k = i;
			for (j = i + 1; j<N; j++)
			{
				if (arr[j] < arr[k]){
					k = j;
				}
			}
			int temp = arr[i];
			arr[i] = arr[k];
			arr[k] = temp;
		}
	}
};

// 具体策略:插入排序
class InsertSort :public Strategy
{
public:
	InsertSort(){
		printf("插入排序\n");
	}
	void sort(int arr[], int N){
		int i, j;
		for (i = 1; i<N; i++)
		{
			for (j = i - 1; j >= 0; j--)
			{
				if (arr[i]>arr[j]){
					break;
				}
			}
			int temp = arr[i];
			for (int k = i - 1; k > j; k--){
				arr[k + 1] = arr[k];
			}
			arr[j + 1] = temp;
		}
	}
};

#endif

Context.h

#include <iostream>
#include "Context.h"

int main(){    
    std::shared_ptr<Context> ctx = std::make_shared<Context>();  
    int arr[] = { 10, 23, -1, 0, 300, 87, 28, 77, -32, 2 };
    ctx->setInput(arr, sizeof(arr) / sizeof(int));
    std::cout << "input: ";
    ctx->print();

    std::shared_ptr<BubbleSort> bubbleSort = std::make_shared<BubbleSort>();
    ctx->setSortStrategy(bubbleSort);
    ctx->sort();

    std::shared_ptr<SelectionSort> selectionSort = std::make_shared<SelectionSort>();
    ctx->setSortStrategy(selectionSort);
    ctx->sort();

    std::shared_ptr<InsertSort> insertSort = std::make_shared<InsertSort>();
    ctx->setSortStrategy(insertSort);
    ctx->sort();

    return 0;
}

main.cpp

#include <iostream>
#include "Context.h"

int main(){    
    std::shared_ptr<Context> ctx = std::make_shared<Context>();  
    int arr[] = { 10, 23, -1, 0, 300, 87, 28, 77, -32, 2 };
    ctx->setInput(arr, sizeof(arr) / sizeof(int));
    std::cout << "input: ";
    ctx->print();

    std::shared_ptr<BubbleSort> bubbleSort = std::make_shared<BubbleSort>();
    ctx->setSortStrategy(bubbleSort);
    ctx->sort();

    std::shared_ptr<SelectionSort> selectionSort = std::make_shared<SelectionSort>();
    ctx->setSortStrategy(selectionSort);
    ctx->sort();

    std::shared_ptr<InsertSort> insertSort = std::make_shared<InsertSort>();
    ctx->setSortStrategy(insertSort);
    ctx->sort();

    return 0;
}

⑧ 模版方法模式

FingerprintModule.h

#ifndef __FINGERPRINTMODULE_H__
#define __FINGERPRINTMODULE_H__

#include <iostream>

// 基类
class FingerprintModule{
public:
	void getImage(){
		std::cout << "采指纹图像\n";
	}
	void output(){
		std::cout << "指纹图像处理完成!\n";		
	}

	virtual bool isSafeMode() = 0;
	virtual void processImage() = 0;
	// 加解密
	virtual void encrypt() = 0;
	virtual void decrypt() = 0;

	// 模板方法
	void algorithm(){
		// 1.采图
		getImage();
		// 2.安全模式下加密和解密
		if (isSafeMode())
		{
			// 2.1. 加密
			encrypt();
			// 2.2. 解密
			decrypt();
		}
		// 3.处理Image
		processImage();
		// 4.处理结果
		output();
	}
};

// 派生类A
class FingerprintModuleA : public FingerprintModule{
public:
	bool isSafeMode(){
		std::cout << "安全模式\n";		
		return true;
	}
	void processImage(){
		std::cout << "使用 第一代版本算法 处理指纹图像\n";									
	}
	void encrypt(){
		std::cout << "使用RSA密钥加密\n";	
	}
	void decrypt(){
		std::cout << "使用RSA密钥解密\n";	
	}
};

// 派生类B
class FingerprintModuleB : public FingerprintModule{
public:
	bool isSafeMode(){
		std::cout << "非安全模式\n";		
		return false;
	}
	void processImage(){
		std::cout << "使用 第二代版本算法 处理指纹图像\n";									
	}
	void encrypt(){}
	void decrypt(){}
};

// 派生类C
class FingerprintModuleC : public FingerprintModule{
public:
	bool isSafeMode(){
		std::cout << "安全模式\n";		
		return true;
	}
	void processImage(){
		std::cout << "使用 第一代版本算法 处理指纹图像\n";									
	}
	void encrypt(){
		std::cout << "使用DH密钥加密\n";	
	}
	void decrypt(){
		std::cout << "使用DH密钥解密\n";	
	}
};

#endif

main.cpp

#include <iostream>
#include "FingerprintModule.h"

int main(){    
    std::shared_ptr<FingerprintModuleA> fa = std::make_shared<FingerprintModuleA>();
    fa->algorithm();

    std::cout << "\n";
    std::shared_ptr<FingerprintModuleB> fb = std::make_shared<FingerprintModuleB>();
    fb->algorithm();

    std::cout << "\n";
    std::shared_ptr<FingerprintModuleC> fc = std::make_shared<FingerprintModuleC>();
    fc->algorithm();

    return 0;
}

2.cmake相关

cmake教程_乒乒乓乓丫的博客-CSDN博客

例1  开源项目GitHub - qicosmos/rest_rpc: modern C++(C++11), simple, easy to use rpc framework

若直接运行server目录下的main.cpp会报错如下:'rest_rpc.hpp' file not found

原因是各头文件的路径是按CMakeLists.txt的include_directories() 来实现的:

所以,通过cmake的方式来组织文件关系, 上面的那个server目录下的main.cpp里的#include <rest_rpc.hpp> 就相当于 #include <../../include/rest_rpc.hpp>。

同理其他的如:

通过cmake执行如下:

3.网络编程

从零开始的C++网络编程 - 知乎

【阅读】《Linux高性能服务器编程》——第五章:Linux网络编程基础API - 知乎

【C++】Web服务器项目所用到的函数详解_c++ iovec_半路杀出来的小黑同学的博客-CSDN博客

TinyWebServer——从0到服务器开发! - 知乎

① 基于socket网络编程的客户端和服务端举例

server.cpp

#include <iostream>
#include <sys/socket.h>   // socket, bind
#include <sys/errno.h>    // errno
#include <netinet/in.h>   // sockaddr_in
#include <cstring>        // bzero   
#include <signal.h>       // signal   
#include <unistd.h>       // close

#define BUFFSIZE     2048
#define DEFAULT_PORT 16555
#define MAXLINK      2048

int sockfd, connfd;       // 定义服务端套接字和客户端套接字

void stopServerRunning(int){    
    close(sockfd);    
    std::cout << "Close Server\n";
    exit(0);
}

int main(){
    sockaddr_in servaddr; // 结构体
    char buff[BUFFSIZE];  // 用于收发数据
    // 在Server端和Client端都有一个socket,通过将socket当作文件,可以写入也可读取
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd == -1){
        std::cout << "Create socket error: " << errno 
        << ", :" << strerror(errno) << "\n";
        return -1;
    }
    // void bzero(void* s, int n);//s为内存(字符串)指针,n为需要清零的字节数。
    bzero(&servaddr, sizeof(servaddr));
    // sin_family指代协议族,在socket编程中只能是AF_INET
    servaddr.sin_family = AF_INET;      
    // sin_addr存储IP地址,使用in_addr这个数据结构(in_addr.s_addr就是32位IP地址),按照网络字节顺序存储IP地址
    // htonl(Host to Network Long)把本机字节顺序转化为网络字节顺序,htons(Host to Network Short)
    // INADDR_ANY转换过来就是0.0.0.0,泛指本机的意思,也就是表示本机的所有IP
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(DEFAULT_PORT);      
    // bind用来给socket绑定地址信息  
    // 通常服务器在启动时会绑定一个总所周知的地址(ip地址+端口号),客户端不用指定系统自动分配,
    // 所以通常服务端在listen之前要调用bind(),而客户端不会调用,在connect()时由系统随机生成一个。
    if(bind(sockfd, (sockaddr*)&servaddr, sizeof(servaddr)) == -1){
        std::cout << "Bind error: " << errno 
        << ", :" << strerror(errno) << "\n";
        return -1;
    }
    if(listen(sockfd, MAXLINK) == -1){
        std::cout << "Listen error: " << errno 
        << ", :" << strerror(errno) << "\n";
        return -1;
    }
    std::cout << "Listening...\n";

    while (true){
        // 这句用于在输入Ctrl+C的时候关闭服务器
        signal(SIGINT, stopServerRunning);     
        connfd = accept(sockfd, nullptr, nullptr);   
        if(connfd == -1){
            std::cout << "Accept error: " << errno 
            << ", :" << strerror(errno) << "\n";
            return -1;
        }
        bzero(buff, BUFFSIZE);
        recv(connfd, buff, BUFFSIZE - 1, 0);
        std::cout << "Recv: " << buff << "\n";
        send(connfd, buff, strlen(buff), 0);
        close(connfd);
    }    

    return 0;
}


client.cpp

#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>        // sockaddr_in
#include <arpa/inet.h>         // inet_pton
#include <unistd.h>            // close

#define BUFFSIZE    2048
#define SERVER_IP   "0.0.0.0"  // 指定服务端的IP,记得修改为你的服务端所在的ip
#define SERVER_PORT 16555      // 指定服务端的port

int main(){
    sockaddr_in servaddr;
    char buff[BUFFSIZE];
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd == -1){
        std::cout << "Create socket error: " << errno 
        << ", :" << strerror(errno) << "\n";
        return -1;
    }
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;   
    // IP地址转换函数: 将点分十进制的ip地址转化为用于网络传输的数值格式
    inet_pton(AF_INET, SERVER_IP, &servaddr.sin_addr);
    servaddr.sin_port = htons(SERVER_PORT);  
    if(connect(sockfd, (sockaddr*)&servaddr, sizeof(servaddr))){
        std::cout << "Connect socket error: " << errno 
        << ", :" << strerror(errno) << "\n";
        return -1;
    }
    std::cout << "Please input: \n";
    scanf("%s", buff);
    send(sockfd, buff, strlen(buff), 0);
    bzero(buff, sizeof(buff));
    recv(sockfd, buff, BUFFSIZE - 1, 0);
    std::cout << "Recv: " << buff << "\n";
    close(sockfd);

    return 0;
}

其中解决地址已占用问题:

 

通信效果如下:

② 30天自制C++服务器学习

GitHub - yuesong-feng/30dayMakeCppServer: 30天自制C++服务器,包含教程和源代码

(1)从一个最简单的socket开始 

server.cpp

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>

int main() {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in serv_addr;
    bzero(&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_addr.sin_port = htons(8888);

    bind(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr));

    listen(sockfd, SOMAXCONN);
    
    struct sockaddr_in clnt_addr;
    socklen_t clnt_addr_len = sizeof(clnt_addr);
    bzero(&clnt_addr, sizeof(clnt_addr));

    int clnt_sockfd = accept(sockfd, (sockaddr*)&clnt_addr, &clnt_addr_len);

    printf("new client fd %d! IP: %s Port: %d\n", clnt_sockfd, inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port));
    return 0;
}

client.cpp

#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>

int main() {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in serv_addr;
    bzero(&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_addr.sin_port = htons(8888);

    //bind(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)); 客户端不进行bind操作

    connect(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr));    
    
    return 0;
}

至此,day01的教程已经结束了,进入code/day01文件夹,使用make命令编译,将会得到serverclient。输入命令./server开始运行,直到accept函数,程序阻塞、等待客户端连接。然后在一个新终端输入命令./client运行客户端,可以看到服务器接收到了客户端的连接请求,并成功连接。

new client fd 3! IP: 127.0.0.1 Port: 53505

但如果我们先运行客户端、后运行服务器,在客户端一侧无任何区别,却并没有连接服务器成功,因为我们day01的程序没有任何的错误处理。

事实上对于如socket,bind,listen,accept,connect等函数,通过返回值以及errno可以确定程序运行的状态、是否发生错误。在day02的教程中,我们会进一步完善整个服务器,处理所有可能的错误,并实现一个echo服务器(客户端发送给服务器一个字符串,服务器收到后返回相同的内容)。

(2)不要放过任何一个错误

util.h

#ifndef UTIL_H
#define UTIL_H

void errif(bool, const char*);

#endif

util.cpp

#include "util.h"
#include <stdio.h>
#include <stdlib.h>

void errif(bool condition, const char *errmsg){
    if(condition){
        perror(errmsg);
        exit(EXIT_FAILURE);
    }
}

server.cpp

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include "util.h"

int main() {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    errif(sockfd == -1, "socket create error");

    struct sockaddr_in serv_addr;
    bzero(&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_addr.sin_port = htons(8888);

    errif(bind(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)) == -1, "socket bind error");

    errif(listen(sockfd, SOMAXCONN) == -1, "socket listen error");
    
    struct sockaddr_in clnt_addr;
    socklen_t clnt_addr_len = sizeof(clnt_addr);
    bzero(&clnt_addr, sizeof(clnt_addr));

    int clnt_sockfd = accept(sockfd, (sockaddr*)&clnt_addr, &clnt_addr_len);
    errif(clnt_sockfd == -1, "socket accept error");

    printf("new client fd %d! IP: %s Port: %d\n", clnt_sockfd, inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port));
    while (true) {
        char buf[1024];
        bzero(&buf, sizeof(buf));
        ssize_t read_bytes = read(clnt_sockfd, buf, sizeof(buf));
        if(read_bytes > 0){
            printf("message from client fd %d: %s\n", clnt_sockfd, buf);
            write(clnt_sockfd, buf, sizeof(buf));
        } else if(read_bytes == 0){
            printf("client fd %d disconnected\n", clnt_sockfd);
            close(clnt_sockfd);
            break;
        } else if(read_bytes == -1){
            close(clnt_sockfd);
            errif(true, "socket read error");
        }
    }
    close(sockfd);
    return 0;
}

client.cpp

#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include "util.h"


int main() {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    errif(sockfd == -1, "socket create error");

    struct sockaddr_in serv_addr;
    bzero(&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_addr.sin_port = htons(8888);

    errif(connect(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)) == -1, "socket connect error");
    
    while(true){
        char buf[1024];
        bzero(&buf, sizeof(buf));
        scanf("%s", buf);
        ssize_t write_bytes = write(sockfd, buf, sizeof(buf));
        if(write_bytes == -1){
            printf("socket already disconnected, can't write any more!\n");
            break;
        }
        bzero(&buf, sizeof(buf));
        ssize_t read_bytes = read(sockfd, buf, sizeof(buf));
        if(read_bytes > 0){
            printf("message from server: %s\n", buf);
        }else if(read_bytes == 0){
            printf("server socket disconnected!\n");
            break;
        }else if(read_bytes == -1){
            close(sockfd);
            errif(true, "socket read error");
        }
    }
    close(sockfd);
    return 0;
}

至此,我们已经完整地开发了一个echo服务器,并且有最基本的错误处理!

但现在,我们的服务器只能处理一个客户端,我们可以试试两个客户端同时连接服务器,看程序将会如何运行。在day03的教程里,我们将会讲解Linux系统高并发的基石--epoll,并编程实现一个可以支持无数客户端同时连接的echo服务器!

(3)高并发还得用epoll 

server.cpp

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <errno.h>
#include "util.h"

#define MAX_EVENTS  1024
#define READ_BUFFER 1024

// 设置非阻塞 
void setnonblocking(int fd){
    // 设置文件的flags: fcntl(fd,F_SETFL,flags);     
    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
}

int main(){
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    errif(sockfd == -1, "socket create error");
    
    struct sockaddr_in serv_addr;
    bzero(&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_addr.sin_port = htons(8888);

    errif(bind(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)) == -1, "socket bind error");

    errif(listen(sockfd, SOMAXCONN) == -1, "socket listen error");

    // 创建一个epoll文件描述符并返回,失败则返回-1
    int epfd = epoll_create1(0);
    errif(epfd == -1, "epoll create error");

    struct epoll_event events[MAX_EVENTS], ev;
    bzero(&events, sizeof(events));
    bzero(&ev, sizeof(ev));
    ev.data.fd = sockfd;                                        // 该IO口为服务器socket fd(文件描述符)
    // EPOLLIN:LT模式,EPOLLET:ET模式
    ev.events  = EPOLLIN;                                       // 服务端最好不要用ET模式
    setnonblocking(sockfd);
    // 将服务器socket fd添加到epoll
    epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);

    while (1){
        // epoll_wait获取有事件发生的fd      
        // 最大等待时间,设置为-1表示一直等待  
        int nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);    // 有nfds个fd发生事件
        errif(nfds == -1, "epoll wait error");

        for(int i = 0; i < nfds; ++i){
            if(events[i].data.fd == sockfd){                    // 发生事件的fd是服务器socket fd,表示有新客户端连接

                struct sockaddr_in clnt_addr;
                bzero(&clnt_addr, sizeof(clnt_addr));
                socklen_t clnt_addr_len = sizeof(clnt_addr);

                int clnt_sockfd = accept(sockfd, (sockaddr*)&clnt_addr, &clnt_addr_len);
                errif(clnt_sockfd == -1, "socket accept error");
                printf("new client fd %d! IP: %s Port: %d\n", clnt_sockfd, inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port));

                bzero(&ev, sizeof(ev));
                ev.data.fd = clnt_sockfd;
                ev.events = EPOLLIN | EPOLLET;                   // 对于客户端连接,使用ET模式,可以让epoll更加高效,支持更多并发
                setnonblocking(clnt_sockfd);                     // ET需要搭配非阻塞式socket使用
                epoll_ctl(epfd, EPOLL_CTL_ADD, clnt_sockfd, &ev);
            }else if (events[i].events & EPOLLIN){               // 发生事件的是客户端,并且是可读事件(EPOLLIN)
                
                char buf[READ_BUFFER];
                while(true){                                     //由于使用非阻塞IO,读取客户端buffer,一次读取buf大小数据,直到全部读取完毕
                    bzero(&buf, sizeof(buf));
                    ssize_t bytes_read = read(events[i].data.fd, buf, sizeof(buf));

                    if(bytes_read > 0){
                        
                        // 保存读取到的bytes_read大小的数据
                        printf("message from client fd %d: %s\n", events[i].data.fd, buf);
                        write(events[i].data.fd, buf, sizeof(buf));
                    }else if(bytes_read == -1 && errno == EINTR){ // 客户端正常中断、继续读取

                        printf("continue reading");
                        continue;
                    }else if(bytes_read == -1 && ((errno == EAGAIN) || (errno == EWOULDBLOCK))){ // 非阻塞IO,这个条件表示数据全部读取完毕

                        printf("finish reading once, errno: %d\n", errno);
                        break;
                    }else if(bytes_read == 0){                    // EOF,客户端断开连接
                    
                        printf("EOF, client fd %d disconnected\n", events[i].data.fd);
                        close(events[i].data.fd);                 // 关闭socket会自动将文件描述符从epoll树上移除
                        break;
                    }
                }
            }else{ //其他事件,之后的版本实现
                printf("something else happened\n");
            }            
        }
    }
    close(sockfd);
    
    return 0;
}

client.cpp

#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include "util.h"

#define BUFFER_SIZE 1024 

int main(){
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    errif(sockfd == -1, "socket create error");

    struct sockaddr_in serv_addr;
    bzero(&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_addr.sin_port = htons(8888);

    errif(connect(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)) == -1, "socket connect error");

    while (1){
        char buf[BUFFER_SIZE];  //在这个版本,buf大小必须大于或等于服务器端buf大小,不然会出错,想想为什么?
        bzero(&buf, sizeof(buf));
        scanf("%s", buf);
        ssize_t write_bytes = write(sockfd, buf, sizeof(buf));
        if(write_bytes == -1){
            printf("socket already disconnected, can't write any more!\n");
            break;
        }

        bzero(&buf, sizeof(buf));
        ssize_t read_bytes = read(sockfd, buf, sizeof(buf));
        if(read_bytes > 0){
            printf("message from server: %s\n", buf);
        }else if(read_bytes == 0){
            printf("server socket disconnected!\n");
            break;
        }else if(read_bytes == -1){
            close(sockfd);
            errif(true, "socket read error");
        }
    }    
    close(sockfd);

    return 0;
}

(4)来看看我们的第一个类

InetAddress.h

#pragma once
 
#include <iostream>
#include <arpa/inet.h>
 
class InetAddress{
public:
    InetAddress();
    InetAddress(std::string ip, uint16_t port);
    
    struct sockaddr_in getAddr(){
        return addr;
    }
 
    socklen_t getAddrLen(){
        return addr_len;
    }
    
private:
    struct sockaddr_in addr;
    socklen_t addr_len;    
};

 InetAddress.cpp

#include <iostream>
#include<string.h>
 
#include "InetAddress.h"
 
InetAddress::InetAddress() : addr_len(sizeof(addr)){
    bzero(&addr, sizeof(addr));
}
 
InetAddress::InetAddress(std::string ip, uint16_t port) : addr_len(sizeof(addr)){
    bzero(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(ip.c_str());
    addr.sin_port = htons(port);
}

Socket.h

#pragma once
 
#include <iostream>
#include <tr1/memory>
 
#include "InetAddress.h"
 
class Socket{
public:
    Socket();    
    Socket(int);  
    ~Socket();  
 
    void bind(InetAddress*);
    void listen();
    void setnonblocking();
 
    int accept(InetAddress*);
 
    int getFd();
 
private:
    int fd; // 文件描述符
};

 Socket.cpp

#include "Socket.h"
#include "InetAddress.h"
#include "util.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <iostream>
#include <tr1/memory>
 
Socket::Socket() : fd(-1){
    fd = socket(AF_INET, SOCK_STREAM, 0);
    errif(fd == -1, "socket create error");
}
 
Socket::Socket(int fd_) : fd(fd_){
    errif(fd == -1, "socket create error");
}
 
Socket::~Socket(){
    if(fd != -1){
        close(fd);
        fd = -1;
    }
}

void Socket::bind(InetAddress *addr){
    struct sockaddr_in addrTmp = addr->getAddr();
    socklen_t addrLen = addr->getAddrLen();
    errif(::bind(fd, (sockaddr*)&addrTmp, addrLen) == -1, "socket bind error");
}
 
void Socket::listen(){
    errif(::listen(fd, SOMAXCONN) == -1, "socket listen error");
}
 
void Socket::setnonblocking(){
    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
}

int Socket::accept(InetAddress *addr){
    struct sockaddr_in addrTmp = addr->getAddr();
    socklen_t addrLen = addr->getAddrLen();
    int clnt_sockfd = ::accept(fd, (sockaddr*)&addrTmp, &addrLen);
    errif(clnt_sockfd == -1, "socket accept error");
    return clnt_sockfd;
}
 
int Socket::getFd(){
    return fd;
}

Epoll.h

#pragma once
 
#include <sys/epoll.h>
#include <iostream>
#include <vector>
 
class Epoll{
public:
    Epoll();
    ~Epoll();
    void addFd(int fd, uint32_t op);
    std::vector<epoll_event> poll(int timeout = -1);
 
private:
    int epfd;
    epoll_event* events;
};

 Epoll.cpp

#include "Epoll.h"
#include "util.h"
#include <unistd.h>
#include <string.h>
#include <iostream>
 
#define MAX_EVENTS 1000
 
Epoll::Epoll() : epfd(-1), events(nullptr){
    epfd = epoll_create1(0);
    errif(epfd == -1, "epoll create error");
    events = new epoll_event[MAX_EVENTS];
    bzero(events, sizeof(*events) * MAX_EVENTS);
} 
 
Epoll::~Epoll(){
    if(epfd != -1){
        close(epfd);
        epfd = -1;
    }
 
    delete[] events; // 防止内存泄漏
}
 
void Epoll::addFd(int fd, uint32_t op){
    struct epoll_event ev;
    bzero(&ev, sizeof(ev));
    ev.data.fd = fd;
    ev.events = op;
    errif(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1, "epoll add event error");
}
 
std::vector<epoll_event> Epoll::poll(int timeout){
    std::vector<epoll_event> activeEvents;
    int nfds = epoll_wait(epfd, events, MAX_EVENTS, timeout);
    errif(nfds == -1, "epoll wait error");
    for(int i = 0; i < nfds; ++i){
        activeEvents.push_back(events[i]);
    }
    
    return activeEvents;
}

server.cpp

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <vector>
#include "util.h"
#include "Epoll.h"
#include "InetAddress.h"
#include "Socket.h"
#include <iostream>
 
#define MAX_EVENTS 1024
#define READ_BUFFER 1024
 
void setnonblocking(int fd){
    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
}
 
void handleReadEvent(int);

int main() {
    Socket *serv_sock = new Socket();
    InetAddress *serv_addr = new InetAddress("127.0.0.1", 8888);
    serv_sock->bind(serv_addr);
    serv_sock->listen();    
    Epoll *ep = new Epoll();
    serv_sock->setnonblocking();
    ep->addFd(serv_sock->getFd(), EPOLLIN | EPOLLET);

    while(true){
        std::vector<epoll_event> events = ep->poll();
        int nfds = events.size();
        for(int i = 0; i < nfds; ++i){
            if(events[i].data.fd == serv_sock->getFd()){  // 新客户端连接
                // new InetAddress() 位置只能在这里!
                InetAddress *clnt_addr = new InetAddress();      
                Socket *clnt_sock = new Socket(serv_sock->accept(clnt_addr));       
                printf("new client fd %d! IP: %s Port: %d\n", clnt_sock->getFd(), 
                       inet_ntoa(clnt_addr->getAddr().sin_addr), ntohs(clnt_addr->getAddr().sin_port));
                clnt_sock->setnonblocking();
                ep->addFd(clnt_sock->getFd(), EPOLLIN | EPOLLET);
            } else if(events[i].events & EPOLLIN){       // 可读事件
                handleReadEvent(events[i].data.fd);
            } else{  // 其他事件,之后的版本实现
                printf("something else happened\n");
            }
        }
    }
    delete serv_sock;
    delete serv_addr;
    delete ep;

    return 0;
}
 
void handleReadEvent(int sockfd){
    char buf[READ_BUFFER];
    while (1){                       // 由于使用非阻塞IO,读取客户端buffer,一次读取buf大小数据,直到全部读取完毕
        bzero(&buf, sizeof(buf));
        ssize_t bytes_read = read(sockfd, buf, sizeof(buf));
        if(bytes_read > 0){
            printf("message from client fd %d: %s\n", sockfd, buf);
            write(sockfd, buf, sizeof(buf));
        } else if(bytes_read == -1 && errno == EINTR){  // 客户端正常中断、继续读取
            printf("continue reading");
            continue;
        } else if(bytes_read == -1 && ((errno == EAGAIN) || (errno == EWOULDBLOCK))){ // 非阻塞IO,这个条件表示数据全部读取完毕
            printf("finish reading once, errno: %d\n", errno);
            break;
        } else if(bytes_read == 0){  // EOF,客户端断开连接
            printf("EOF, client fd %d disconnected\n", sockfd);
            close(sockfd);           // 关闭socket会自动将文件描述符从epoll树上移除
            break;
        }
    }
}

client.cpp

#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include "util.h"

#define BUFFER_SIZE 1024 

int main(){
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    errif(sockfd == -1, "socket create error");

    struct sockaddr_in serv_addr;
    bzero(&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_addr.sin_port = htons(8888);

    errif(connect(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)) == -1, "socket connect error");

    while (1){
        char buf[BUFFER_SIZE];  //在这个版本,buf大小必须大于或等于服务器端buf大小,不然会出错,想想为什么?
        bzero(&buf, sizeof(buf));
        scanf("%s", buf);
        ssize_t write_bytes = write(sockfd, buf, sizeof(buf));
        if(write_bytes == -1){
            printf("socket already disconnected, can't write any more!\n");
            break;
        }

        bzero(&buf, sizeof(buf));
        ssize_t read_bytes = read(sockfd, buf, sizeof(buf));
        if(read_bytes > 0){
            printf("message from server: %s\n", buf);
        }else if(read_bytes == 0){
            printf("server socket disconnected!\n");
            break;
        }else if(read_bytes == -1){
            close(sockfd);
            errif(true, "socket read error");
        }
    }    
    close(sockfd);

    return 0;
}
g++ util.cpp client.cpp -o client && \
g++ util.cpp server.cpp Epoll.cpp InetAddress.cpp Socket.cpp -o server

至此,我们已经完整地开发了一个echo服务器,并且引入面向对象编程的思想,初步封装了SocketInetAddressEpoll,大大精简了主程序,隐藏了底层语言实现细节、增加了可读性。

4. spdlog源码学习

https://www.cnblogs.com/shuqin/p/12214439.html

https://www.cnblogs.com/fortunely/p/17388565.html

简介:

  • 提供的 日志格式 非常丰富,并且允许用户自定义需要的格式。
  • 对日志文件的类型也做了充分扩展,支持控制台,普通文件,按大小滚动文件,按时间滚动文件,如果不能满足需要,可以自己扩展格式,见 spdlog/sinks/base_sink.h
  • 支持单/多线程,异步/同步,阻塞非阻塞模式

文件结构:

代码逻辑结构: 

 

有几个比较重要的文件:

  • spdlog/spdlog.h 为日志库接口,提供日志宏的属性控制函数。
  • spdlog/logger.h 为日志管理器,为前后端连接的枢纽。
  • spdlog/async.h 为异步模式接口。
  • spdlog/sinks/base_sink.h 为日志文件格式父类,后面所有的日志文件格式都是继承该类来实现不同功能。
  • spdlog/sinks/registry.h 用于登记所有的logger,及一些默认的属性,如日志格式、日志写入等级。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值