当前位置:   article > 正文

c++ 常用总结(三)_std::shared_ptr

std::shared_ptr

1.设计模式 

 GitHub - FengJungle/DesignPattern: Design pattern demo code

(一) 

① 简单工厂模式

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

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

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

例1

SimpleFactory.h

  1. #ifndef _SIMPLE_FACTORY_
  2. #define _SIMPLE_FACTORY_
  3. #include <iostream>
  4. // 抽象类
  5. class AbstractSportProduct{
  6. public:
  7. virtual void printName() = 0;
  8. virtual void play() = 0;
  9. };
  10. class Basketball : public AbstractSportProduct{
  11. public:
  12. void printName(){std::cout << "Jungle get Basketball\n";}
  13. void play(){std::cout << "Jungle play Basketball\n";}
  14. };
  15. class Football : public AbstractSportProduct{
  16. public:
  17. Football(){
  18. printName();
  19. play();
  20. }
  21. void printName(){std::cout << "Jungle get Football\n";}
  22. void play(){std::cout << "Jungle play Football\n";}
  23. };
  24. class Volleyball : public AbstractSportProduct{
  25. public:
  26. void printName(){std::cout << "Jungle get Volleyball\n";}
  27. void play(){std::cout << "Jungle play Volleyball\n";}
  28. };
  29. class Factory{
  30. public:
  31. std::shared_ptr<AbstractSportProduct> getSportProduct(std::string productName){
  32. std::shared_ptr<AbstractSportProduct> pro;
  33. if(productName == "Basketball"){
  34. pro = std::make_shared<Basketball>();
  35. }else if (productName == "Football"){
  36. pro = std::make_shared<Football>();
  37. }else if (productName == "Volleyball"){
  38. pro = std::make_shared<Volleyball>();
  39. }
  40. return pro;
  41. }
  42. };
  43. #endif

main.cpp

  1. #include <iostream>
  2. #include "SimpleFactory.h"
  3. int main(){
  4. std::shared_ptr<Factory> f = std::make_shared<Factory>();
  5. std::shared_ptr<AbstractSportProduct> pro = f->getSportProduct("Basketball");
  6. pro->printName();
  7. pro->play();
  8. std::cout << "-------------------------\n";
  9. pro = f->getSportProduct("Football");
  10. std::cout << "-------------------------\n";
  11. pro = f->getSportProduct("Volleyball");
  12. pro->printName();
  13. pro->play();
  14. return 0;
  15. }

② 工厂模式

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

例1

FactoryMethod.h

  1. #ifndef __FACTORY_METHOD__
  2. #define __FACTORY_METHOD__
  3. #include <iostream>
  4. // 抽象产品类
  5. class AbstractSportProduct{
  6. public:
  7. virtual void printName() = 0;
  8. virtual void play() = 0;
  9. };
  10. class Basketball :public AbstractSportProduct{
  11. public:
  12. void printName(){std::cout << "Jungle get Basketball\n";}
  13. void play(){std::cout << "Jungle play Basketball\n";}
  14. };
  15. class Football :public AbstractSportProduct{
  16. public:
  17. Football(){
  18. printName();
  19. play();
  20. }
  21. void printName(){std::cout << "Jungle get Football\n";}
  22. void play(){std::cout << "Jungle play Football\n";}
  23. };
  24. class Volleyball :public AbstractSportProduct{
  25. public:
  26. void printName(){std::cout << "Jungle get Volleyball\n";}
  27. void play(){std::cout << "Jungle play Volleyball\n";}
  28. };
  29. // 抽象工厂类
  30. class AbstractFactory{
  31. public:
  32. virtual std::shared_ptr<AbstractSportProduct> getSportProduct() = 0;
  33. };
  34. class BasketballFactory : public AbstractFactory{
  35. public:
  36. std::shared_ptr<AbstractSportProduct> getSportProduct() {
  37. return std::make_shared<Basketball>();
  38. }
  39. };
  40. class FootballFactory : public AbstractFactory{
  41. public:
  42. std::shared_ptr<AbstractSportProduct> getSportProduct() {
  43. return std::make_shared<Football>();
  44. }
  45. };
  46. class VolleyballFactory : public AbstractFactory{
  47. public:
  48. std::shared_ptr<AbstractSportProduct> getSportProduct() {
  49. return std::make_shared<Volleyball>();
  50. }
  51. };
  52. #endif

main.cpp

  1. #include <iostream>
  2. #include "FactoryMethod.h"
  3. int main(){
  4. std::shared_ptr<BasketballFactory> f = std::make_shared<BasketballFactory>();
  5. std::shared_ptr<AbstractSportProduct> pro = f->getSportProduct();
  6. pro->printName();
  7. pro->play();
  8. std::cout << "------------------------------\n";
  9. std::shared_ptr<FootballFactory> f1 = std::make_shared<FootballFactory>();
  10. pro = f1->getSportProduct();
  11. std::cout << "------------------------------\n";
  12. std::shared_ptr<VolleyballFactory> f2 = std::make_shared<VolleyballFactory>();
  13. pro = f2->getSportProduct();
  14. pro->printName();
  15. pro->play();
  16. return 0;
  17. }

③ 抽象工厂模式

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

例1

AbstractFactory.h

  1. #ifndef __ABSTRACT_FACTORY__
  2. #define __ABSTRACT_FACTORY__
  3. #include <iostream>
  4. // 抽象球类
  5. class AbstractBall{
  6. public:
  7. virtual void play() = 0;
  8. };
  9. class Basketball : public AbstractBall{
  10. public:
  11. void play() {std::cout << "Jungle play Basketball\n";}
  12. };
  13. class Football : public AbstractBall{
  14. public:
  15. void play() {std::cout << "Jungle play Football\n";}
  16. };
  17. // 抽象衬衫类
  18. class AbstractShirt{
  19. public:
  20. virtual void wearShirt() = 0;
  21. };
  22. class BasketballShirt : public AbstractShirt{
  23. public:
  24. void wearShirt() {std::cout << "Jungle wear Basketball Shirt\n";}
  25. };
  26. class FootballShirt : public AbstractShirt{
  27. public:
  28. void wearShirt() {std::cout << "Jungle wear Football Shirt\n";}
  29. };
  30. // 抽象工厂类
  31. class AbstractFactory{
  32. public:
  33. virtual std::shared_ptr<AbstractBall> getBall() = 0;
  34. virtual std::shared_ptr<AbstractShirt> getShirt() = 0;
  35. };
  36. class BasketballFactory : public AbstractFactory{
  37. public:
  38. std::shared_ptr<AbstractBall> getBall(){
  39. std::cout << "Jungle get Basketball\n";
  40. return std::make_shared<Basketball>();
  41. }
  42. std::shared_ptr<AbstractShirt> getShirt(){
  43. std::cout << "Jungle get Basketball Shirt\n";
  44. return std::make_shared<BasketballShirt>();
  45. }
  46. };
  47. class FootballFactory : public AbstractFactory{
  48. public:
  49. std::shared_ptr<AbstractBall> getBall(){
  50. std::cout << "Jungle get Football\n";
  51. return std::make_shared<Football>();
  52. }
  53. std::shared_ptr<AbstractShirt> getShirt(){
  54. std::cout << "Jungle get Football Shirt\n";
  55. return std::make_shared<FootballShirt>();
  56. }
  57. };
  58. #endif

main.cpp

  1. #include <iostream>
  2. #include "AbstractFactory.h"
  3. int main(){
  4. std::shared_ptr<BasketballFactory> f = std::make_shared<BasketballFactory>();
  5. std::shared_ptr<AbstractBall> ab = f->getBall();
  6. std::shared_ptr<AbstractShirt> as = f->getShirt();
  7. ab->play();
  8. as->wearShirt();
  9. std::cout << "---------------------------------\n";
  10. std::shared_ptr<FootballFactory> f1 = std::make_shared<FootballFactory>();
  11. ab = f1->getBall();
  12. as = f1->getShirt();
  13. ab->play();
  14. as->wearShirt();
  15. return 0;
  16. }

④ 建造者模式

例1

BuilderPattern.h

  1. #ifndef __BUILDER_PATTERN__
  2. #define __BUILDER_PATTERN__
  3. #include <iostream>
  4. // 产品类
  5. class House{
  6. public:
  7. void setFloor(std::string iFloor){
  8. this->floor = iFloor;
  9. }
  10. void setWall(std::string iWall){
  11. this->wall = iWall;
  12. }
  13. void setRoof(std::string iRoof){
  14. this->roof = iRoof;
  15. }
  16. void printfHouseInfo() {
  17. std::cout << "floor: " << floor << "\n";
  18. std::cout << "wall: " << wall << "\n";
  19. std::cout << "roof: " << roof << "\n";
  20. }
  21. private:
  22. std::string floor;
  23. std::string wall;
  24. std::string roof;
  25. };
  26. // 抽象建造者
  27. class AbstractBuilder{
  28. public:
  29. AbstractBuilder(){house = std::make_shared<House>();}
  30. virtual void buildFloor() = 0;
  31. virtual void buildWall() = 0;
  32. virtual void buildRoof() = 0;
  33. virtual std::shared_ptr<House> getHouse() = 0;
  34. std::shared_ptr<House> house;
  35. };
  36. // 具体建造者A
  37. class ConcreteBuilderA : public AbstractBuilder{
  38. public:
  39. void buildFloor() {
  40. house->setFloor("Floor_A");
  41. }
  42. void buildWall(){
  43. house->setWall("Wall_A");
  44. }
  45. void buildRoof(){
  46. house->setRoof("Roof_A");
  47. }
  48. std::shared_ptr<House> getHouse(){
  49. return house;
  50. }
  51. };
  52. // 具体建造者B
  53. class ConcreteBuilderB : public AbstractBuilder{
  54. public:
  55. void buildFloor() {
  56. house->setFloor("Floor_B");
  57. }
  58. void buildWall(){
  59. house->setWall("Wall_B");
  60. }
  61. void buildRoof(){
  62. house->setRoof("Roof_B");
  63. }
  64. std::shared_ptr<House> getHouse(){
  65. return house;
  66. }
  67. };
  68. // 指挥者
  69. class Director{
  70. public:
  71. void setBuilder(std::shared_ptr<AbstractBuilder> ibuilder){
  72. builder = ibuilder;
  73. }
  74. // 封装组装流程,返回建造结果
  75. std::shared_ptr<House> construct(){
  76. builder->buildFloor();
  77. builder->buildRoof();
  78. builder->buildWall();
  79. return builder->getHouse();
  80. }
  81. private:
  82. std::shared_ptr<AbstractBuilder> builder;
  83. };
  84. #endif

main.cpp

  1. #include <iostream>
  2. #include "BuilderPattern.h"
  3. int main(){
  4. // 指定具体建造者A
  5. std::shared_ptr<Director> d = std::make_shared<Director>();
  6. std::shared_ptr<ConcreteBuilderA> cba = std::make_shared<ConcreteBuilderA>();
  7. d->setBuilder(cba);
  8. std::shared_ptr<House> h = d->construct();
  9. h->printfHouseInfo();
  10. std::cout << "---------------------------\n";
  11. // 指定具体建造者B
  12. std::shared_ptr<ConcreteBuilderB> cbb = std::make_shared<ConcreteBuilderB>();
  13. d->setBuilder(cbb);
  14. h = d->construct();
  15. h->printfHouseInfo();
  16. return 0;
  17. }

⑤ 原型模式

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

例1

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

PrototypePattern.h

  1. #ifndef __PROTOTYPE_PATTERN__
  2. #define __PROTOTYPE_PATTERN__
  3. #include <iostream>
  4. class WorkModel{
  5. public:
  6. void setWorkModelName(std::string imodelName){
  7. modelName = imodelName;
  8. }
  9. std::string getWorkModelName(){
  10. return modelName;
  11. }
  12. private:
  13. std::string modelName;
  14. };
  15. class ConcreteWork {
  16. public:
  17. std::shared_ptr<ConcreteWork> clone(){
  18. std::shared_ptr<ConcreteWork> cw = std::make_shared<ConcreteWork>();
  19. cw->setIdNum(idNum);
  20. cw->setIdName(idName);
  21. cw->setIWorkModel(iWorkModel);
  22. return cw;
  23. }
  24. std::shared_ptr<WorkModel> getIWorkModel(){
  25. return iWorkModel;
  26. }
  27. void setIdNum(int iIdNum){
  28. idNum = iIdNum;
  29. }
  30. void setIdName(std::string iIdName){
  31. idName = iIdName;
  32. }
  33. void setIWorkModel(std::shared_ptr<WorkModel> iIWorkModel){
  34. iWorkModel = iIWorkModel;
  35. }
  36. void printWorkInfo(){
  37. std::cout << "Name: " << idName << "\n";
  38. std::cout << "Num: " << idNum << "\n";
  39. std::cout << "ModelName: " << iWorkModel->getWorkModelName() << "\n";
  40. }
  41. private:
  42. int idNum;
  43. std::string idName;
  44. std::shared_ptr<WorkModel> iWorkModel;
  45. };
  46. #endif

main.cpp 

  1. #include <iostream>
  2. #include "PrototypePattern.h"
  3. int main(){
  4. std::shared_ptr<ConcreteWork> singleWork = std::make_shared<ConcreteWork>();
  5. singleWork->setIdNum(1001);
  6. singleWork->setIdName("single");
  7. std::shared_ptr<WorkModel> singleWorkModel = singleWork->getIWorkModel();
  8. // 错:singleWorkModel是空指针,执行setWorkModelName()会报错!
  9. singleWorkModel->setWorkModelName("single_model");
  10. std::cout << "single完成了作业:\n";
  11. return 0;
  12. }

改正如下:

PrototypePattern.h

  1. #ifndef __PROTOTYPE_PATTERN__
  2. #define __PROTOTYPE_PATTERN__
  3. #include <iostream>
  4. class WorkModel{
  5. public:
  6. void setWorkModelName(std::string imodelName){
  7. modelName = imodelName;
  8. }
  9. std::string getWorkModelName(){
  10. return modelName;
  11. }
  12. private:
  13. std::string modelName;
  14. };
  15. class ConcreteWork {
  16. public:
  17. std::shared_ptr<ConcreteWork> clone(){
  18. std::shared_ptr<ConcreteWork> cw = std::make_shared<ConcreteWork>();
  19. cw->setIdNum(idNum);
  20. cw->setIdName(idName);
  21. cw->setIWorkModel(iWorkModel);
  22. return cw;
  23. }
  24. void setIdNum(int iIdNum){
  25. idNum = iIdNum;
  26. }
  27. void setIdName(std::string iIdName){
  28. idName = iIdName;
  29. }
  30. void setIWorkModel(std::shared_ptr<WorkModel> iIWorkModel){
  31. iWorkModel = iIWorkModel;
  32. }
  33. void printWorkInfo(){
  34. std::cout << "Name: " << idName << "\n";
  35. std::cout << "Num: " << idNum << "\n";
  36. std::cout << "ModelName: " << iWorkModel->getWorkModelName() << "\n";
  37. }
  38. private:
  39. int idNum;
  40. std::string idName;
  41. std::shared_ptr<WorkModel> iWorkModel;
  42. };
  43. #endif

main.cpp 

  1. #include <iostream>
  2. #include "PrototypePattern.h"
  3. int main(){
  4. std::shared_ptr<ConcreteWork> singleWork = std::make_shared<ConcreteWork>();
  5. singleWork->setIdNum(1001);
  6. singleWork->setIdName("single");
  7. std::shared_ptr<WorkModel> workModel = std::make_shared<WorkModel>();
  8. workModel->setWorkModelName("single_model");
  9. singleWork->setIWorkModel(workModel);
  10. singleWork->printWorkInfo();
  11. std::shared_ptr<ConcreteWork> jungleWork = singleWork->clone();
  12. std::cout << "jungle正在抄作业...\n";
  13. std::cout << "jungle抄完了,正在改名字和学号,否则会被老师查出来...\n";
  14. jungleWork->setIdNum(1002);
  15. jungleWork->setIdName("jungle");
  16. workModel = std::make_shared<WorkModel>();
  17. workModel->setWorkModelName("jungle_Model");
  18. jungleWork->setIWorkModel(workModel);
  19. std::cout << "jungle也完成了作业:\n";
  20. jungleWork->printWorkInfo();
  21. return 0;
  22. }

⑥ 单例模式

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

Singleton.h

  1. #ifndef __SINGLETON_H__
  2. #define __SINGLETON_H__
  3. #include <iostream>
  4. #include <mutex>
  5. std::mutex m_mutex;
  6. // 懒汉单例模式
  7. class Singleton_Lazy{
  8. public:
  9. static std::shared_ptr<Singleton_Lazy> getInstance(){
  10. std::cout << "singleton lazy mode.\n";
  11. if(instance == nullptr){
  12. m_mutex.lock(); // 加锁
  13. if(instance == nullptr){
  14. std::cout << "创建新的实例.\n";
  15. instance = std::make_shared<Singleton_Lazy>();
  16. }
  17. m_mutex.unlock(); // 解锁
  18. }
  19. return instance;
  20. }
  21. private:
  22. static std::shared_ptr<Singleton_Lazy> instance;
  23. };
  24. std::shared_ptr<Singleton_Lazy> Singleton_Lazy::instance = nullptr;
  25. // 饿汉单例模式
  26. class Singleton_Hungry{
  27. public:
  28. static std::shared_ptr<Singleton_Hungry> getInstance(){
  29. std::cout << "singleton hungry mode.\n";
  30. instance = std::make_shared<Singleton_Hungry>();
  31. return instance;
  32. }
  33. private:
  34. static std::shared_ptr<Singleton_Hungry> instance;
  35. };
  36. std::shared_ptr<Singleton_Hungry> Singleton_Hungry::instance = nullptr;
  37. #endif

main.cpp

  1. #include <iostream>
  2. #include "Singleton.h"
  3. #include <pthread.h>
  4. #define THREAD_NUM 6
  5. void* callSingleton_Lazy(void*){
  6. std::shared_ptr<Singleton_Lazy> sl = Singleton_Lazy::getInstance();
  7. std::cout << "线程编号: " << pthread_self() << "\n";
  8. }
  9. void* callSingleton_Hungry(void*){
  10. std::shared_ptr<Singleton_Hungry> sh = Singleton_Hungry::getInstance();
  11. std::cout << "线程编号: " << pthread_self() << "\n";
  12. }
  13. int main(){
  14. pthread_t threads_pool[THREAD_NUM];
  15. int tids[THREAD_NUM];
  16. // 线程具有属性,用pthread_attr_t表示,在对该结构进行处理之前必须进行初始化,在使用后需要对其去除初始化。
  17. pthread_attr_t attr;
  18. void* status;
  19. // 创建 pthread_attr_t
  20. pthread_attr_init(&attr);
  21. // 线程的分离状态决定一个线程以什么样的方式来终止自己。在默认情况下线程是非分离状态的,这种情况下,原有的线程等待创建的线程结束。
  22. // 只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。
  23. // PTHREAD _CREATE_JOINABLE(非分离线程)
  24. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  25. for(int i = 0; i < THREAD_NUM; i++){
  26. if(i < THREAD_NUM / 2){
  27. // 线程创建 pthread_create
  28. tids[i] = pthread_create(&threads_pool[i], nullptr, callSingleton_Lazy, (void*)&i);
  29. }else {
  30. std::cout << "-----------------\n";
  31. tids[i] = pthread_create(&threads_pool[i], nullptr, callSingleton_Hungry, (void*)&i);
  32. }
  33. if(tids[i]){
  34. std::cout << "Error: unable to create thread.\n";
  35. return 0;
  36. }
  37. }
  38. // 销毁 pthread_attr_t
  39. pthread_attr_destroy(&attr);
  40. for(int i = 0; i < THREAD_NUM; i++){
  41. // pthread_join 主线程阻塞
  42. tids[i] = pthread_join(threads_pool[i], &status);
  43. if(tids[i]){
  44. std::cout << "Error: unable to join.\n";
  45. return 0;
  46. }
  47. }
  48. std::cout << "main exiting.\n";
  49. return 0;
  50. }

⑦ 适配器模式

AdapterPattern.h

  1. #ifndef __ADAPTERPATTERN_H__
  2. #define __ADAPTERPATTERN_H__
  3. #include <iostream>
  4. // 适配者类DxfParser
  5. class DxfParser{
  6. public:
  7. void parseFile(){
  8. std::cout << "Parse dxf file\n";
  9. }
  10. };
  11. // 适配者类PathPlanner
  12. class PathPlanner{
  13. public:
  14. void calculate(){
  15. std::cout << "calculate path\n";
  16. }
  17. };
  18. class Adapter{
  19. public:
  20. void pathPlanning(){
  21. std::cout << "pathPlanning\n";
  22. dxfParser->parseFile();
  23. pathPlanner->calculate();
  24. }
  25. private:
  26. std::shared_ptr<DxfParser> dxfParser;
  27. std::shared_ptr<PathPlanner> pathPlanner;
  28. };
  29. #endif

main.cpp 

  1. #include <iostream>
  2. #include "AdapterPattern.h"
  3. int main(){
  4. std::shared_ptr<Adapter> adapter = std::make_shared<Adapter>();
  5. adapter->pathPlanning();
  6. return 0;
  7. }

⑧  桥接模式

BridgePattern.h

  1. #ifndef __BRIDGE_PATTERN_H__
  2. #define __BRIDGE_PATTERN_H__
  3. #include <iostream>
  4. // 抽象类Game
  5. class Game{
  6. public:
  7. virtual void play() = 0;
  8. };
  9. class GameA : public Game {
  10. public:
  11. void play(){
  12. std::cout << "Jungle玩游戏A\n";
  13. }
  14. };
  15. class GameB : public Game {
  16. public:
  17. void play(){
  18. std::cout << "Jungle玩游戏B\n";
  19. }
  20. };
  21. // 抽象类Phone
  22. class Phone{
  23. public:
  24. virtual void setUpGame(std::shared_ptr<Game> igame) = 0;
  25. virtual void play() = 0;
  26. private:
  27. std::shared_ptr<Game> game;
  28. };
  29. class PhoneA : public Phone{
  30. public:
  31. void setUpGame(std::shared_ptr<Game> igame){
  32. game = igame;
  33. }
  34. void play(){
  35. game->play();
  36. }
  37. private:
  38. std::shared_ptr<Game> game;
  39. };
  40. class PhoneB : public Phone{
  41. public:
  42. void setUpGame(std::shared_ptr<Game> igame){
  43. game = igame;
  44. }
  45. void play(){
  46. game->play();
  47. }
  48. private:
  49. std::shared_ptr<Game> game;
  50. };
  51. #endif

main.cpp

  1. #include <iostream>
  2. #include "BridgePattern.h"
  3. int main(){
  4. // Jungle买了PhoneA品牌的手机,想玩游戏A
  5. std::shared_ptr<PhoneA> phoneA = std::make_shared<PhoneA>();
  6. std::shared_ptr<GameA> gameA = std::make_shared<GameA>();
  7. phoneA->setUpGame(gameA);
  8. phoneA->play();
  9. std::cout << "----------------\n";
  10. // Jungle想在这个手机上玩游戏B
  11. std::shared_ptr<GameB> gameB = std::make_shared<GameB>();
  12. phoneA->setUpGame(gameB);
  13. phoneA->play();
  14. return 0;
  15. }

⑨  组合模式

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

CompositePattern.h

  1. #ifndef __COMPOSITE_PATTERN_H__
  2. #define __COMPOSITE_PATTERN_H__
  3. #include <iostream>
  4. #include <vector>
  5. // 抽象构件
  6. class Component{
  7. public:
  8. Component(){}
  9. Component(std::string iName){name = iName;}
  10. // 增加一个部门或办公室
  11. virtual void add(std::shared_ptr<Component> com) = 0;
  12. // 撤销一个部门或办公室
  13. virtual void remove(std::shared_ptr<Component> com) = 0;
  14. //
  15. virtual std::shared_ptr<Component> getChild(int num) = 0;
  16. // 各部门操作
  17. virtual void operation() = 0;
  18. std::string getName(){
  19. return name;
  20. }
  21. private:
  22. std::string name;
  23. };
  24. // 叶子构件:办公室
  25. // 没实现operation(),所以抽象类Component的子类Office也是抽象类,不能实例化!
  26. class Office : public Component{
  27. public:
  28. Office(){}
  29. Office(std::string iName){name = iName;}
  30. void add(std::shared_ptr<Component> com){
  31. std::cout << "not support!\n";
  32. }
  33. void remove(std::shared_ptr<Component> com){
  34. std::cout << "not support!\n";
  35. }
  36. std::shared_ptr<Component> getChild(int num){
  37. std::cout << "not support!\n";
  38. return nullptr;
  39. }
  40. private:
  41. std::string name;
  42. };
  43. // 叶子构件:行政办公室
  44. // 虽然没实现add()、remove()、getChild(),但其基类Office已经实现过了这部分 ——>
  45. // 所以派生类AdminOffice虽然只实现了operation(), 但其仍然可以实例化!
  46. class AdminOffice : public Office{
  47. public:
  48. AdminOffice(){}
  49. AdminOffice(std::string iName){name = iName;}
  50. void operation(){
  51. std::cout << "-----Administration Office: " << name << "\n";
  52. }
  53. private:
  54. std::string name;
  55. };
  56. // 叶子构件:教务办公室
  57. // 可以实例化,原因同AdminOffice
  58. class DeanOffice : public Office{
  59. public:
  60. DeanOffice(){}
  61. DeanOffice(std::string iName){name = iName;}
  62. void operation(){
  63. std::cout << "-----Dean Office: " << name << "\n";
  64. }
  65. private:
  66. std::string name;
  67. };
  68. // 容器构件SubComponent
  69. // 实现了Component的所有纯虚函数,所以SubComponent可以实例化!
  70. class SubComponent : public Component{
  71. public:
  72. SubComponent(){}
  73. SubComponent(std::string iName){
  74. name = iName;
  75. }
  76. void add(std::shared_ptr<Component> com){
  77. componentList.push_back(com);
  78. }
  79. void remove(std::shared_ptr<Component> com){
  80. for(int i = 0; i < componentList.size(); i++){
  81. // 遍历查找
  82. if(componentList[i]->getName() == com->getName()){
  83. componentList.erase(componentList.begin() + 1);
  84. break;
  85. }
  86. }
  87. }
  88. std::shared_ptr<Component> getChild(int num){
  89. return componentList[num];
  90. }
  91. void operation(){
  92. std::cout << name << "\n";
  93. for(int i = 0; i < componentList.size(); i++){
  94. componentList[i]->operation();
  95. }
  96. }
  97. private:
  98. std::string name;
  99. // 构件列表
  100. std::vector<std::shared_ptr<Component> > componentList;
  101. };
  102. #endif

main.cpp

  1. #include <iostream>
  2. #include "CompositePattern.h"
  3. int main(){
  4. std::shared_ptr<SubComponent> head = std::make_shared<SubComponent>("总部");
  5. std::shared_ptr<SubComponent> sichuanBranch = std::make_shared<SubComponent>("四川分部");
  6. std::shared_ptr<AdminOffice> office1 = std::make_shared<AdminOffice>("行政办公室");
  7. std::shared_ptr<DeanOffice> office2 = std::make_shared<DeanOffice>("教务办公室");
  8. std::shared_ptr<SubComponent> cdBranch = std::make_shared<SubComponent>("成都分部");
  9. std::shared_ptr<SubComponent> myBranch = std::make_shared<SubComponent>("绵阳分部");
  10. std::shared_ptr<AdminOffice> office3 = std::make_shared<AdminOffice>("行政办公室");
  11. std::shared_ptr<DeanOffice> office4 = std::make_shared<DeanOffice>("教务办公室");
  12. std::shared_ptr<AdminOffice> office5 = std::make_shared<AdminOffice>("行政办公室");
  13. std::shared_ptr<DeanOffice> office6 = std::make_shared<DeanOffice>("教务办公室");
  14. std::shared_ptr<AdminOffice> office7 = std::make_shared<AdminOffice>("行政办公室");
  15. std::shared_ptr<DeanOffice> office8 = std::make_shared<DeanOffice>("教务办公室");
  16. cdBranch->add(office5);
  17. cdBranch->add(office6);
  18. myBranch->add(office7);
  19. myBranch->add(office8);
  20. sichuanBranch->add(office3);
  21. sichuanBranch->add(office4);
  22. sichuanBranch->add(cdBranch);
  23. sichuanBranch->add(myBranch);
  24. head->add(office1);
  25. head->add(office2);
  26. head->add(sichuanBranch);
  27. head->operation();
  28. return 0;
  29. }

⑩  装饰模式

DecoratorPattern.h

  1. #ifndef __DECORATOR_PATTERN_H__
  2. #define __DECORATOR_PATTERN_H__
  3. #include <iostream>
  4. // 抽象构件
  5. class Component{
  6. public:
  7. virtual void operation() = 0;
  8. };
  9. // 具体构件
  10. class Phone : public Component{
  11. public:
  12. void operation(){
  13. std::cout << "手机\n";
  14. }
  15. };
  16. class Decorator : public Component{
  17. public:
  18. void operation(){
  19. component->operation();
  20. }
  21. void setComponent(std::shared_ptr<Component> iComponent){
  22. component = iComponent;
  23. }
  24. std::shared_ptr<Component> getComponent(){
  25. return component;
  26. }
  27. private:
  28. std::shared_ptr<Component> component;
  29. };
  30. // 具体装饰类:手机壳
  31. class DecoratorShell : public Decorator{
  32. public:
  33. void operation(){
  34. getComponent()->operation();
  35. std::cout << "安装手机壳\n";
  36. }
  37. };
  38. // 具体装饰类:手机贴纸
  39. class DecoratorSticker : public Decorator{
  40. public:
  41. void operation(){
  42. getComponent()->operation();
  43. std::cout << "贴卡通贴纸ֽ\n";
  44. }
  45. };
  46. // 具体装饰类:挂绳
  47. class DecoratorRope : public Decorator{
  48. public:
  49. void operation(){
  50. getComponent()->operation();
  51. std::cout << "系手机挂绳\n";
  52. }
  53. };
  54. #endif

main.cpp

  1. #include <iostream>
  2. #include "DecoratorPattern.h"
  3. int main(){
  4. std::cout << "Jungle's first phone\n";
  5. std::shared_ptr<Phone> p = std::make_shared<Phone>();
  6. std::shared_ptr<DecoratorShell> ds = std::make_shared<DecoratorShell>();
  7. ds->setComponent(p);
  8. ds->operation();
  9. std::cout << "\nJungle's second phone\n";
  10. std::shared_ptr<DecoratorSticker> dst = std::make_shared<DecoratorSticker>();
  11. dst->setComponent(ds);
  12. dst->operation();
  13. std::cout << "\nJungle's third phone\n";
  14. std::shared_ptr<DecoratorRope> dr = std::make_shared<DecoratorRope>();
  15. dr->setComponent(dst);
  16. dr->operation();
  17. return 0;
  18. }

(二)

① 外观模式

FacadePattern.h

  1. /*
  2. * @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
  3. * @Date: 2021-08-19 11:19:57
  4. * @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
  5. * @LastEditTime: 2023-03-13 10:29:14
  6. * @FilePath: /cpp_test/FacadePattern.h
  7. * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE#
  8. */
  9. #ifndef __FACADE_PATTERN_H__
  10. #define __FACADE_PATTERN_H__
  11. #include <iostream>
  12. class Memory{
  13. public:
  14. void selfCheck(){
  15. std::cout << "memory selfchecking......\n";
  16. }
  17. };
  18. class Cpu{
  19. public:
  20. void run(){
  21. std::cout << "running cpu......\n";
  22. }
  23. };
  24. class HardDisk{
  25. public:
  26. void read(){
  27. std::cout << "reading hardDisk......\n";
  28. }
  29. };
  30. class Os{
  31. public:
  32. void load(){
  33. std::cout << "loading os.....\n";
  34. }
  35. };
  36. class Facade{
  37. public:
  38. void powerOn(){
  39. std::cout << "power on……\n";
  40. memory->selfCheck();
  41. cpu->run();
  42. hardDisk->read();
  43. os->load();
  44. std::cout << "ready!\n";
  45. }
  46. private:
  47. std::shared_ptr<Memory> memory;
  48. std::shared_ptr<Cpu> cpu;
  49. std::shared_ptr<HardDisk> hardDisk;
  50. std::shared_ptr<Os> os;
  51. };
  52. #endif

main.cpp

  1. #include <iostream>
  2. #include "FacadePattern.h"
  3. int main(){
  4. std::shared_ptr<Facade> f = std::make_shared<Facade>();
  5. f->powerOn();
  6. return 0;
  7. }

② 享元模式

FlyweightPattern.h

  1. /*
  2. * @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
  3. * @Date: 2021-08-19 11:19:57
  4. * @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
  5. * @LastEditTime: 2023-03-13 11:23:46
  6. * @FilePath: /cpp_test/FlyweightPattern.h
  7. * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  8. */
  9. #ifndef __FLYPATTERN_PATTERN_H__
  10. #define __FLYPATTERN_PATTERN_H__
  11. #include <iostream>
  12. #include <vector>
  13. #include <mutex>
  14. std::mutex m_mutex;
  15. // 抽象享元类
  16. class NetDevice{
  17. public:
  18. virtual std::string getName() = 0;
  19. void print(int portNum){
  20. std::cout << "NetDevice: " << getName() << ", port: " << portNum << "\n";
  21. }
  22. };
  23. // 具体享元类:集线器
  24. class Hub : public NetDevice{
  25. public:
  26. std::string getName(){
  27. return "集线器";
  28. }
  29. };
  30. // 具体享元类:交换机
  31. class Switch : public NetDevice{
  32. public:
  33. std::string getName(){
  34. return "交换机";
  35. }
  36. };
  37. // 享元工厂类
  38. class NetDeviceFactory{
  39. public:
  40. NetDeviceFactory(){
  41. std::shared_ptr<Hub> hub = std::make_shared<Hub>();
  42. std::shared_ptr<Switch> switcher = std::make_shared<Switch>();
  43. devicePool.push_back(hub);
  44. devicePool.push_back(switcher);
  45. }
  46. std::shared_ptr<NetDevice> getNetDevice(char c){
  47. if(c == 'S'){
  48. return devicePool[1];
  49. }else if (c == 'H')
  50. {
  51. return devicePool[0];
  52. }else{
  53. std::cout << "wrong input!\n";
  54. }
  55. return nullptr;
  56. }
  57. // 单例模式:返回享元工厂类的唯一实例
  58. static std::shared_ptr<NetDeviceFactory> getFactory(){
  59. if(instance == nullptr){
  60. m_mutex.lock();
  61. if(instance == nullptr){
  62. instance = std::make_shared<NetDeviceFactory>();
  63. }
  64. m_mutex.unlock();
  65. }
  66. return instance;
  67. }
  68. private:
  69. static std::shared_ptr<NetDeviceFactory> instance;
  70. // 共享池
  71. std::vector<std::shared_ptr<NetDevice> > devicePool;
  72. };
  73. std::shared_ptr<NetDeviceFactory> NetDeviceFactory::instance = nullptr;
  74. #endif

main.cpp

  1. #include <iostream>
  2. #include "FlyweightPattern.h"
  3. int main(){
  4. std::shared_ptr<NetDeviceFactory> netDeviceFactory = NetDeviceFactory::getFactory();
  5. // 客户端1获取一个hub
  6. std::shared_ptr<NetDevice> netDevice1 = netDeviceFactory->getNetDevice('H');
  7. netDevice1->print(1);
  8. // 客户端2获取一个hub
  9. std::shared_ptr<NetDevice> netDevice2 = netDeviceFactory->getNetDevice('H');
  10. netDevice2->print(2);
  11. std::cout << "判断两个hub是否是同一个:\n";
  12. std::cout << "netDevice1: " << netDevice1 << ", netDevice2: " << netDevice2 << "\n\n\n";
  13. // 客户端3获取一个switch
  14. std::shared_ptr<NetDevice> netDevice3 = netDeviceFactory->getNetDevice('S');
  15. netDevice3->print(1);
  16. // 客户端4获取一个switch
  17. std::shared_ptr<NetDevice> netDevice4 = netDeviceFactory->getNetDevice('S');
  18. netDevice4->print(2);
  19. std::cout << "判断两个switch是否是同一个:\n";
  20. std::cout << "netDevice3: " << netDevice3 << ", netDevice4: " << netDevice4 << "\n";
  21. return 0;
  22. }

③ 代理模式

报错如下:

ProxyPattern.h

  1. #ifndef __FLYPATTERN_PATTERN_H__
  2. #define __FLYPATTERN_PATTERN_H__
  3. #include <iostream>
  4. #include "time.h"
  5. // 抽象主题角色
  6. class Subject{
  7. public:
  8. virtual void method() = 0;
  9. };
  10. // 真实主题角色
  11. class RealSubject : public Subject{
  12. public:
  13. void method(){
  14. std::cout << "调用业务方法\n";
  15. }
  16. };
  17. // Log类
  18. class Log{
  19. public:
  20. void getLog(){
  21. std::cout << "调用日志\n";
  22. }
  23. };
  24. // 代理类
  25. class Proxy : public Subject{
  26. public:
  27. void method(){
  28. log->getLog();
  29. realSubject->method();
  30. std::cout << "方法method()调用成功!\n";
  31. }
  32. private:
  33. std::shared_ptr<RealSubject> realSubject;
  34. std::shared_ptr<Log> log;
  35. };
  36. #endif

main.cpp

  1. #include <iostream>
  2. #include "ProxyPattern.h"
  3. int main(){
  4. std::shared_ptr<Proxy> p = std::make_shared<Proxy>();
  5. p->method();
  6. return 0;
  7. }

修改如下:

ProxyPattern.h

  1. #ifndef __FLYPATTERN_PATTERN_H__
  2. #define __FLYPATTERN_PATTERN_H__
  3. #include <iostream>
  4. #include "time.h"
  5. // 抽象主题角色
  6. class Subject{
  7. public:
  8. virtual void method() = 0;
  9. };
  10. // 真实主题角色
  11. class RealSubject : public Subject{
  12. public:
  13. void method(){
  14. std::cout << "调用业务方法\n";
  15. }
  16. };
  17. // Log类
  18. class Log{
  19. public:
  20. void getLog(){
  21. std::cout << "调用日志\n";
  22. }
  23. };
  24. // 代理类
  25. class Proxy : public Subject{
  26. public:
  27. Proxy(){
  28. realSubject = std::make_shared<RealSubject>();
  29. log = std::make_shared<Log>();
  30. }
  31. void method(){
  32. log->getLog();
  33. realSubject->method();
  34. std::cout << "方法method()调用成功!\n";
  35. }
  36. private:
  37. std::shared_ptr<RealSubject> realSubject;
  38. std::shared_ptr<Log> log;
  39. };
  40. #endif

也可修改如下:

ProxyPattern.h

  1. #ifndef __FLYPATTERN_PATTERN_H__
  2. #define __FLYPATTERN_PATTERN_H__
  3. #include <iostream>
  4. #include "time.h"
  5. // 抽象主题角色
  6. class Subject{
  7. public:
  8. virtual void method() = 0;
  9. };
  10. // 真实主题角色
  11. class RealSubject : public Subject{
  12. public:
  13. void method(){
  14. std::cout << "调用业务方法\n";
  15. }
  16. };
  17. // Log类
  18. class Log{
  19. public:
  20. void getLog(){
  21. std::cout << "调用日志\n";
  22. }
  23. };
  24. // 代理类
  25. class Proxy : public Subject{
  26. public:
  27. void method(){
  28. realSubject = std::make_shared<RealSubject>();
  29. log = std::make_shared<Log>();
  30. log->getLog();
  31. realSubject->method();
  32. std::cout << "方法method()调用成功!\n";
  33. }
  34. private:
  35. std::shared_ptr<RealSubject> realSubject;
  36. std::shared_ptr<Log> log;
  37. };
  38. #endif

④  职责链模式

ChainOfResponsibility.h

  1. #ifndef __CHAIN_OF_RESPONSIBILITY_PATTERN_H__
  2. #define __CHAIN_OF_RESPONSIBILITY_PATTERN_H__
  3. #include <iostream>
  4. // 请求:票据
  5. class Bill{
  6. public:
  7. Bill(){}
  8. Bill(int iId, std::string iName, double iAccount){
  9. id = iId;
  10. name = iName;
  11. account = iAccount;
  12. }
  13. void print(){
  14. std::cout << "id: " << id << "\n";
  15. std::cout << "name: " << name << "\n";
  16. std::cout << "account: " << account << "\n\n";
  17. }
  18. double getAccount(){
  19. return account;
  20. }
  21. private:
  22. int id;
  23. std::string name;
  24. double account;
  25. };
  26. // 抽象处理者
  27. class Approver{
  28. public:
  29. // 添加上级
  30. void setSuperior(std::shared_ptr<Approver> iApprover){
  31. superior = iApprover;
  32. }
  33. // 处理请求
  34. virtual void handleRequest(std::shared_ptr<Bill> bill) = 0;
  35. std::shared_ptr<Approver> getSuperior(){
  36. return superior;
  37. }
  38. std::string getName(){
  39. return name;
  40. }
  41. void setName(std::string iName){
  42. name = iName;
  43. }
  44. private:
  45. std::shared_ptr<Approver> superior;
  46. std::string name;
  47. };
  48. // 具体处理者:组长
  49. class GroupLeader : public Approver{
  50. public:
  51. GroupLeader(){}
  52. GroupLeader(std::string iName){
  53. setName(iName);
  54. }
  55. void handleRequest(std::shared_ptr<Bill> bill){
  56. if(bill->getAccount() < 10){
  57. std::cout << "组长: " << getName() << "处理了该票据,票据信息:\n";
  58. bill->print();
  59. }else{
  60. std::cout << "组长无权处理,转交上级……\n";
  61. getSuperior()->handleRequest(bill);
  62. }
  63. }
  64. };
  65. // 具体处理者:主管
  66. class Head : public Approver{
  67. public:
  68. Head(){}
  69. Head(std::string iName){
  70. setName(iName);
  71. }
  72. void handleRequest(std::shared_ptr<Bill> bill){
  73. if(bill->getAccount() >= 10 && bill->getAccount() < 30){
  74. std::cout << "主管: " << getName() << "处理了该票据,票据信息:\n";
  75. bill->print();
  76. }else{
  77. std::cout << "主管无权处理,转交上级……\n";
  78. getSuperior()->handleRequest(bill);
  79. }
  80. }
  81. };
  82. // 具体处理者:经理
  83. class Manager : public Approver{
  84. public:
  85. Manager(){}
  86. Manager(std::string iName){
  87. setName(iName);
  88. }
  89. void handleRequest(std::shared_ptr<Bill> bill){
  90. if(bill->getAccount() >= 30 && bill->getAccount() < 60){
  91. std::cout << "经理: " << getName() << "处理了该票据,票据信息:\n";
  92. bill->print();
  93. }else{
  94. std::cout << "经理无权处理,转交上级……\n";
  95. getSuperior()->handleRequest(bill);
  96. }
  97. }
  98. };
  99. // 具体处理者:老板
  100. class Boss : public Approver{
  101. public:
  102. Boss(){}
  103. Boss(std::string iName){
  104. setName(iName);
  105. }
  106. void handleRequest(std::shared_ptr<Bill> bill){
  107. std::cout << "老板: " << getName() << "处理了该票据,票据信息:\n";
  108. bill->print();
  109. }
  110. };
  111. #endif

main.cpp

  1. #include <iostream>
  2. #include "ChainOfResponsibility.h"
  3. int main(){
  4. std::shared_ptr<GroupLeader> groupLeader = std::make_shared<GroupLeader>("孙组长");
  5. std::shared_ptr<Head> head = std::make_shared<Head>("兵主管");
  6. std::shared_ptr<Manager> manager = std::make_shared<Manager>("春经理");
  7. std::shared_ptr<Boss> boss = std::make_shared<Boss>("孙老板");
  8. // 添加上级
  9. groupLeader->setSuperior(head);
  10. head->setSuperior(manager);
  11. manager->setSuperior(boss);
  12. // 创建报销单
  13. std::shared_ptr<Bill> bill1 = std::make_shared<Bill>(1, "Jungle", 8);
  14. std::shared_ptr<Bill> bill2 = std::make_shared<Bill>(2, "Lucy", 14.4);
  15. std::shared_ptr<Bill> bill3 = std::make_shared<Bill>(3, "Jack", 32.9);
  16. std::shared_ptr<Bill> bill4 = std::make_shared<Bill>(4, "Tom", 89);
  17. // 全部先交给组长审批
  18. groupLeader->handleRequest(bill1);
  19. groupLeader->handleRequest(bill2);
  20. groupLeader->handleRequest(bill3);
  21. groupLeader->handleRequest(bill4);
  22. return 0;
  23. }

⑤  命令模式

CommandPattern.h

  1. #ifndef __COMMAND_PATTERN_H__
  2. #define __COMMAND_PATTERN_H__
  3. #include <iostream>
  4. #include <vector>
  5. // 命令队列类
  6. #define COMMAND_QUEUE
  7. // 抽象命令类
  8. class Command{
  9. public:
  10. virtual void execute() = 0;
  11. };
  12. // 接收者:电灯类
  13. class Lamp{
  14. public:
  15. void on(){
  16. lampState = true;
  17. std::cout << "Lamp is on\n";
  18. }
  19. void off(){
  20. lampState = false;
  21. std::cout << "Lamp is off\n";
  22. }
  23. bool getLampState(){
  24. return lampState;
  25. }
  26. private:
  27. bool lampState;
  28. };
  29. // 接收者:风扇类
  30. class Fan{
  31. public:
  32. void on(){
  33. fanState = true;
  34. std::cout << "Fan is on\n";
  35. }
  36. void off(){
  37. fanState = false;
  38. std::cout << "Fan is off\n";
  39. }
  40. bool getFanState(){
  41. return fanState;
  42. }
  43. private:
  44. bool fanState;
  45. };
  46. // 具体命令类 LampCommand
  47. class LampCommand : public Command{
  48. public:
  49. LampCommand(){
  50. lamp = std::make_shared<Lamp>();
  51. }
  52. void execute(){
  53. if(lamp->getLampState()){
  54. lamp->off();
  55. }else{
  56. lamp->on();
  57. }
  58. }
  59. private:
  60. std::shared_ptr<Lamp> lamp;
  61. };
  62. // 具体命令类 FanCommand
  63. class FanCommand : public Command{
  64. public:
  65. FanCommand(){
  66. fan = std::make_shared<Fan>();
  67. }
  68. void execute(){
  69. if(fan->getFanState()){
  70. fan->off();
  71. }else{
  72. fan->on();
  73. }
  74. }
  75. private:
  76. std::shared_ptr<Fan> fan;
  77. };
  78. // 调用者 Button
  79. class Button{
  80. public:
  81. void setCommand(std::shared_ptr<Command> iCom){
  82. command = iCom;
  83. }
  84. void touch(){
  85. std::cout << "触摸开关:\n";
  86. command->execute();
  87. }
  88. private:
  89. std::shared_ptr<Command> command;
  90. };
  91. #ifdef COMMAND_QUEUE
  92. // 命令队列类
  93. class CommandQueue{
  94. public:
  95. void addCommand(std::shared_ptr<Command> com){
  96. commandQueue.push_back(com);
  97. }
  98. void execute(){
  99. for(int i = 0; i < commandQueue.size(); i++){
  100. commandQueue[i]->execute();
  101. }
  102. }
  103. private:
  104. std::vector<std::shared_ptr<Command> > commandQueue;
  105. };
  106. // 调用者 Button2
  107. class Button2{
  108. public:
  109. void setCommandQueue(std::shared_ptr<CommandQueue> iCommandQueue){
  110. commandQueue = iCommandQueue;
  111. }
  112. void touch(){
  113. std::cout << "触摸开关:\n";
  114. commandQueue->execute();
  115. }
  116. private:
  117. std::shared_ptr<CommandQueue> commandQueue;
  118. };
  119. #endif
  120. #endif

main.cpp

  1. #include <iostream>
  2. #include "CommandPattern.h"
  3. int main(){
  4. // 按钮
  5. std::shared_ptr<Button> bt = std::make_shared<Button>();
  6. // 按钮控制电灯
  7. std::shared_ptr<LampCommand> lc = std::make_shared<LampCommand>();
  8. bt->setCommand(lc);
  9. bt->touch();
  10. bt->touch();
  11. bt->touch();
  12. bt->touch();
  13. std::cout << "\n\n";
  14. std::shared_ptr<FanCommand> fc = std::make_shared<FanCommand>();
  15. bt->setCommand(fc);
  16. bt->touch();
  17. bt->touch();
  18. bt->touch();
  19. bt->touch();
  20. std::cout << "-------------------------\n";
  21. #ifdef COMMAND_QUEUE
  22. std::shared_ptr<Button2> bt2 = std::make_shared<Button2>();
  23. std::shared_ptr<CommandQueue> cq = std::make_shared<CommandQueue>();
  24. cq->addCommand(lc);
  25. cq->addCommand(fc);
  26. bt2->setCommandQueue(cq);
  27. bt2->touch();
  28. #endif
  29. return 0;
  30. }

⑥ 备忘录模式

Memento.h

  1. #ifndef __MEMENTO_H__
  2. #define __MEMENTO_H__
  3. #include <iostream>
  4. class Memento{
  5. public:
  6. Memento(){}
  7. Memento(int iVersion, std::string iDate, std::string iLabel){
  8. version = iVersion;
  9. date = iDate;
  10. label = iLabel;
  11. }
  12. int getVersion(){
  13. return version;
  14. }
  15. std::string getDate(){
  16. return date;
  17. }
  18. std::string getLabel(){
  19. return label;
  20. }
  21. private:
  22. int version;
  23. std::string date;
  24. std::string label;
  25. };
  26. #endif

Originator.h

  1. #ifndef __CODEVERSION_H__
  2. #define __CODEVERSION_H__
  3. #include <iostream>
  4. #include "Memento.h"
  5. class CodeVersion{
  6. public:
  7. CodeVersion(){
  8. version = 0;
  9. date = "1900-01-01";
  10. label = "none";
  11. }
  12. CodeVersion(int iVersion, std::string iDate, std::string iLabel){
  13. version = iVersion;
  14. date = iDate;
  15. label = iLabel;
  16. }
  17. std::shared_ptr<Memento> save(){
  18. return std::make_shared<Memento>(version, date, label);
  19. }
  20. std::shared_ptr<Memento> commit(){
  21. return std::make_shared<Memento>(version, date, label);
  22. }
  23. void restore(std::shared_ptr<Memento> mem){
  24. version = mem->getVersion();
  25. date = mem->getDate();
  26. label = mem->getLabel();
  27. }
  28. private:
  29. int version;
  30. std::string date;
  31. std::string label;
  32. };
  33. #endif

CodeManager.h 

  1. #ifndef __CODEMANAGER_H__
  2. #define __CODEMANAGER_H__
  3. #include <iostream>
  4. #include <vector>
  5. #include "Memento.h"
  6. class CodeManager{
  7. public:
  8. void commit(std::shared_ptr<Memento> mem){
  9. std::cout << "version: " << mem->getVersion() <<
  10. ", date: " << mem->getDate() << ", label: " << mem->getLabel() << "\n";
  11. mementoList.push_back(mem);
  12. }
  13. std::shared_ptr<Memento> switchToPointedVersion(int index){
  14. mementoList.erase(mementoList.begin() + mementoList.size() - index, mementoList.end());
  15. return mementoList[mementoList.size() - 1];
  16. }
  17. void codeLog(){
  18. for (int i = 0; i < mementoList.size(); i++){
  19. std::cout << "version: " << mementoList[i]->getVersion() <<
  20. ", date: " << mementoList[i]->getDate() << ", label: " << mementoList[i]->getLabel() << "\n";
  21. }
  22. }
  23. private:
  24. std::vector<std::shared_ptr<Memento> > mementoList;
  25. };
  26. #endif

main.cpp

  1. #include <iostream>
  2. #include "Originator.h"
  3. #include "CodeManager.h"
  4. int main(){
  5. std::shared_ptr<CodeManager> Jungle = std::make_shared<CodeManager>();
  6. std::shared_ptr<CodeVersion> codeVer = std::make_shared<CodeVersion>(1001, "2019-11-03", "Initial version");
  7. std::cout << "提交初始版本:\n";
  8. Jungle->commit(codeVer->save());
  9. std::cout << "\n提交一个版本,增加了日志功能:\n";
  10. codeVer = std::make_shared<CodeVersion>(1002, "2019-11-04", "Add log funciton");
  11. Jungle->commit(codeVer->save());
  12. std::cout << "\n提交一个版本,增加了Qt图片浏览器:\n";
  13. codeVer = std::make_shared<CodeVersion>(1003, "2019-11-05", "Add Qt Image Browser");
  14. Jungle->commit(codeVer->save());
  15. std::cout << "\n查看提交历史\n";
  16. Jungle->codeLog();
  17. std::cout << "\n回退到上一个版本\n";
  18. codeVer->restore(Jungle->switchToPointedVersion(1));
  19. std::cout << "\n查看提交历史\n";
  20. Jungle->codeLog();
  21. return 0;
  22. }

⑦ 策略模式

Strategy.h

  1. #ifndef __STRATEGY_H__
  2. #define __STRATEGY_H__
  3. #include <iostream>
  4. // 抽象策略类
  5. class Strategy{
  6. public:
  7. virtual void sort(int arr[], int N) = 0;
  8. };
  9. // 具体策略:冒泡排序
  10. class BubbleSort : public Strategy{
  11. public:
  12. BubbleSort(){
  13. std::cout << "冒泡排序\n";
  14. }
  15. void sort(int arr[], int N){
  16. for (int i = 0; i<N; i++)
  17. {
  18. for (int j = 0; j<N - i - 1; j++)
  19. {
  20. if (arr[j]>arr[j + 1]){
  21. int tmp = arr[j];
  22. arr[j] = arr[j + 1];
  23. arr[j + 1] = tmp;
  24. }
  25. }
  26. }
  27. }
  28. };
  29. // 具体策略:选择排序
  30. class SelectionSort : public Strategy{
  31. public:
  32. SelectionSort(){
  33. std::cout << "选择排序\n";
  34. }
  35. void sort(int arr[], int N){
  36. int i, j, k;
  37. for (i = 0; i<N; i++)
  38. {
  39. k = i;
  40. for (j = i + 1; j<N; j++)
  41. {
  42. if (arr[j] < arr[k]){
  43. k = j;
  44. }
  45. }
  46. int temp = arr[i];
  47. arr[i] = arr[k];
  48. arr[k] = temp;
  49. }
  50. }
  51. };
  52. // 具体策略:插入排序
  53. class InsertSort :public Strategy
  54. {
  55. public:
  56. InsertSort(){
  57. printf("插入排序\n");
  58. }
  59. void sort(int arr[], int N){
  60. int i, j;
  61. for (i = 1; i<N; i++)
  62. {
  63. for (j = i - 1; j >= 0; j--)
  64. {
  65. if (arr[i]>arr[j]){
  66. break;
  67. }
  68. }
  69. int temp = arr[i];
  70. for (int k = i - 1; k > j; k--){
  71. arr[k + 1] = arr[k];
  72. }
  73. arr[j + 1] = temp;
  74. }
  75. }
  76. };
  77. #endif

Context.h

  1. #include <iostream>
  2. #include "Context.h"
  3. int main(){
  4. std::shared_ptr<Context> ctx = std::make_shared<Context>();
  5. int arr[] = { 10, 23, -1, 0, 300, 87, 28, 77, -32, 2 };
  6. ctx->setInput(arr, sizeof(arr) / sizeof(int));
  7. std::cout << "input: ";
  8. ctx->print();
  9. std::shared_ptr<BubbleSort> bubbleSort = std::make_shared<BubbleSort>();
  10. ctx->setSortStrategy(bubbleSort);
  11. ctx->sort();
  12. std::shared_ptr<SelectionSort> selectionSort = std::make_shared<SelectionSort>();
  13. ctx->setSortStrategy(selectionSort);
  14. ctx->sort();
  15. std::shared_ptr<InsertSort> insertSort = std::make_shared<InsertSort>();
  16. ctx->setSortStrategy(insertSort);
  17. ctx->sort();
  18. return 0;
  19. }

main.cpp

  1. #include <iostream>
  2. #include "Context.h"
  3. int main(){
  4. std::shared_ptr<Context> ctx = std::make_shared<Context>();
  5. int arr[] = { 10, 23, -1, 0, 300, 87, 28, 77, -32, 2 };
  6. ctx->setInput(arr, sizeof(arr) / sizeof(int));
  7. std::cout << "input: ";
  8. ctx->print();
  9. std::shared_ptr<BubbleSort> bubbleSort = std::make_shared<BubbleSort>();
  10. ctx->setSortStrategy(bubbleSort);
  11. ctx->sort();
  12. std::shared_ptr<SelectionSort> selectionSort = std::make_shared<SelectionSort>();
  13. ctx->setSortStrategy(selectionSort);
  14. ctx->sort();
  15. std::shared_ptr<InsertSort> insertSort = std::make_shared<InsertSort>();
  16. ctx->setSortStrategy(insertSort);
  17. ctx->sort();
  18. return 0;
  19. }

⑧ 模版方法模式

FingerprintModule.h

  1. #ifndef __FINGERPRINTMODULE_H__
  2. #define __FINGERPRINTMODULE_H__
  3. #include <iostream>
  4. // 基类
  5. class FingerprintModule{
  6. public:
  7. void getImage(){
  8. std::cout << "采指纹图像\n";
  9. }
  10. void output(){
  11. std::cout << "指纹图像处理完成!\n";
  12. }
  13. virtual bool isSafeMode() = 0;
  14. virtual void processImage() = 0;
  15. // 加解密
  16. virtual void encrypt() = 0;
  17. virtual void decrypt() = 0;
  18. // 模板方法
  19. void algorithm(){
  20. // 1.采图
  21. getImage();
  22. // 2.安全模式下加密和解密
  23. if (isSafeMode())
  24. {
  25. // 2.1. 加密
  26. encrypt();
  27. // 2.2. 解密
  28. decrypt();
  29. }
  30. // 3.处理Image
  31. processImage();
  32. // 4.处理结果
  33. output();
  34. }
  35. };
  36. // 派生类A
  37. class FingerprintModuleA : public FingerprintModule{
  38. public:
  39. bool isSafeMode(){
  40. std::cout << "安全模式\n";
  41. return true;
  42. }
  43. void processImage(){
  44. std::cout << "使用 第一代版本算法 处理指纹图像\n";
  45. }
  46. void encrypt(){
  47. std::cout << "使用RSA密钥加密\n";
  48. }
  49. void decrypt(){
  50. std::cout << "使用RSA密钥解密\n";
  51. }
  52. };
  53. // 派生类B
  54. class FingerprintModuleB : public FingerprintModule{
  55. public:
  56. bool isSafeMode(){
  57. std::cout << "非安全模式\n";
  58. return false;
  59. }
  60. void processImage(){
  61. std::cout << "使用 第二代版本算法 处理指纹图像\n";
  62. }
  63. void encrypt(){}
  64. void decrypt(){}
  65. };
  66. // 派生类C
  67. class FingerprintModuleC : public FingerprintModule{
  68. public:
  69. bool isSafeMode(){
  70. std::cout << "安全模式\n";
  71. return true;
  72. }
  73. void processImage(){
  74. std::cout << "使用 第一代版本算法 处理指纹图像\n";
  75. }
  76. void encrypt(){
  77. std::cout << "使用DH密钥加密\n";
  78. }
  79. void decrypt(){
  80. std::cout << "使用DH密钥解密\n";
  81. }
  82. };
  83. #endif

main.cpp

  1. #include <iostream>
  2. #include "FingerprintModule.h"
  3. int main(){
  4. std::shared_ptr<FingerprintModuleA> fa = std::make_shared<FingerprintModuleA>();
  5. fa->algorithm();
  6. std::cout << "\n";
  7. std::shared_ptr<FingerprintModuleB> fb = std::make_shared<FingerprintModuleB>();
  8. fb->algorithm();
  9. std::cout << "\n";
  10. std::shared_ptr<FingerprintModuleC> fc = std::make_shared<FingerprintModuleC>();
  11. fc->algorithm();
  12. return 0;
  13. }

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

  1. #include <iostream>
  2. #include <sys/socket.h> // socket, bind
  3. #include <sys/errno.h> // errno
  4. #include <netinet/in.h> // sockaddr_in
  5. #include <cstring> // bzero
  6. #include <signal.h> // signal
  7. #include <unistd.h> // close
  8. #define BUFFSIZE 2048
  9. #define DEFAULT_PORT 16555
  10. #define MAXLINK 2048
  11. int sockfd, connfd; // 定义服务端套接字和客户端套接字
  12. void stopServerRunning(int){
  13. close(sockfd);
  14. std::cout << "Close Server\n";
  15. exit(0);
  16. }
  17. int main(){
  18. sockaddr_in servaddr; // 结构体
  19. char buff[BUFFSIZE]; // 用于收发数据
  20. // 在Server端和Client端都有一个socket,通过将socket当作文件,可以写入也可读取
  21. sockfd = socket(AF_INET, SOCK_STREAM, 0);
  22. if(sockfd == -1){
  23. std::cout << "Create socket error: " << errno
  24. << ", :" << strerror(errno) << "\n";
  25. return -1;
  26. }
  27. // void bzero(void* s, int n);//s为内存(字符串)指针,n为需要清零的字节数。
  28. bzero(&servaddr, sizeof(servaddr));
  29. // sin_family指代协议族,在socket编程中只能是AF_INET
  30. servaddr.sin_family = AF_INET;
  31. // sin_addr存储IP地址,使用in_addr这个数据结构(in_addr.s_addr就是32位IP地址),按照网络字节顺序存储IP地址
  32. // htonl(Host to Network Long)把本机字节顺序转化为网络字节顺序,htons(Host to Network Short)
  33. // INADDR_ANY转换过来就是0.0.0.0,泛指本机的意思,也就是表示本机的所有IP
  34. servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  35. servaddr.sin_port = htons(DEFAULT_PORT);
  36. // bind用来给socket绑定地址信息
  37. // 通常服务器在启动时会绑定一个总所周知的地址(ip地址+端口号),客户端不用指定系统自动分配,
  38. // 所以通常服务端在listen之前要调用bind(),而客户端不会调用,在connect()时由系统随机生成一个。
  39. if(bind(sockfd, (sockaddr*)&servaddr, sizeof(servaddr)) == -1){
  40. std::cout << "Bind error: " << errno
  41. << ", :" << strerror(errno) << "\n";
  42. return -1;
  43. }
  44. if(listen(sockfd, MAXLINK) == -1){
  45. std::cout << "Listen error: " << errno
  46. << ", :" << strerror(errno) << "\n";
  47. return -1;
  48. }
  49. std::cout << "Listening...\n";
  50. while (true){
  51. // 这句用于在输入Ctrl+C的时候关闭服务器
  52. signal(SIGINT, stopServerRunning);
  53. connfd = accept(sockfd, nullptr, nullptr);
  54. if(connfd == -1){
  55. std::cout << "Accept error: " << errno
  56. << ", :" << strerror(errno) << "\n";
  57. return -1;
  58. }
  59. bzero(buff, BUFFSIZE);
  60. recv(connfd, buff, BUFFSIZE - 1, 0);
  61. std::cout << "Recv: " << buff << "\n";
  62. send(connfd, buff, strlen(buff), 0);
  63. close(connfd);
  64. }
  65. return 0;
  66. }

client.cpp

  1. #include <iostream>
  2. #include <sys/socket.h>
  3. #include <sys/types.h>
  4. #include <netinet/in.h> // sockaddr_in
  5. #include <arpa/inet.h> // inet_pton
  6. #include <unistd.h> // close
  7. #define BUFFSIZE 2048
  8. #define SERVER_IP "0.0.0.0" // 指定服务端的IP,记得修改为你的服务端所在的ip
  9. #define SERVER_PORT 16555 // 指定服务端的port
  10. int main(){
  11. sockaddr_in servaddr;
  12. char buff[BUFFSIZE];
  13. int sockfd = socket(AF_INET, SOCK_STREAM, 0);
  14. if(sockfd == -1){
  15. std::cout << "Create socket error: " << errno
  16. << ", :" << strerror(errno) << "\n";
  17. return -1;
  18. }
  19. bzero(&servaddr, sizeof(servaddr));
  20. servaddr.sin_family = AF_INET;
  21. // IP地址转换函数: 将点分十进制的ip地址转化为用于网络传输的数值格式
  22. inet_pton(AF_INET, SERVER_IP, &servaddr.sin_addr);
  23. servaddr.sin_port = htons(SERVER_PORT);
  24. if(connect(sockfd, (sockaddr*)&servaddr, sizeof(servaddr))){
  25. std::cout << "Connect socket error: " << errno
  26. << ", :" << strerror(errno) << "\n";
  27. return -1;
  28. }
  29. std::cout << "Please input: \n";
  30. scanf("%s", buff);
  31. send(sockfd, buff, strlen(buff), 0);
  32. bzero(buff, sizeof(buff));
  33. recv(sockfd, buff, BUFFSIZE - 1, 0);
  34. std::cout << "Recv: " << buff << "\n";
  35. close(sockfd);
  36. return 0;
  37. }

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

 

通信效果如下:

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

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

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

server.cpp

  1. #include <stdio.h>
  2. #include <sys/socket.h>
  3. #include <arpa/inet.h>
  4. #include <string.h>
  5. int main() {
  6. int sockfd = socket(AF_INET, SOCK_STREAM, 0);
  7. struct sockaddr_in serv_addr;
  8. bzero(&serv_addr, sizeof(serv_addr));
  9. serv_addr.sin_family = AF_INET;
  10. serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  11. serv_addr.sin_port = htons(8888);
  12. bind(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr));
  13. listen(sockfd, SOMAXCONN);
  14. struct sockaddr_in clnt_addr;
  15. socklen_t clnt_addr_len = sizeof(clnt_addr);
  16. bzero(&clnt_addr, sizeof(clnt_addr));
  17. int clnt_sockfd = accept(sockfd, (sockaddr*)&clnt_addr, &clnt_addr_len);
  18. printf("new client fd %d! IP: %s Port: %d\n", clnt_sockfd, inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port));
  19. return 0;
  20. }

client.cpp

  1. #include <sys/socket.h>
  2. #include <arpa/inet.h>
  3. #include <string.h>
  4. int main() {
  5. int sockfd = socket(AF_INET, SOCK_STREAM, 0);
  6. struct sockaddr_in serv_addr;
  7. bzero(&serv_addr, sizeof(serv_addr));
  8. serv_addr.sin_family = AF_INET;
  9. serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  10. serv_addr.sin_port = htons(8888);
  11. //bind(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)); 客户端不进行bind操作
  12. connect(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr));
  13. return 0;
  14. }

至此,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

  1. #ifndef UTIL_H
  2. #define UTIL_H
  3. void errif(bool, const char*);
  4. #endif

util.cpp

  1. #include "util.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. void errif(bool condition, const char *errmsg){
  5. if(condition){
  6. perror(errmsg);
  7. exit(EXIT_FAILURE);
  8. }
  9. }

server.cpp

  1. #include <stdio.h>
  2. #include <sys/socket.h>
  3. #include <arpa/inet.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include "util.h"
  7. int main() {
  8. int sockfd = socket(AF_INET, SOCK_STREAM, 0);
  9. errif(sockfd == -1, "socket create error");
  10. struct sockaddr_in serv_addr;
  11. bzero(&serv_addr, sizeof(serv_addr));
  12. serv_addr.sin_family = AF_INET;
  13. serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  14. serv_addr.sin_port = htons(8888);
  15. errif(bind(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)) == -1, "socket bind error");
  16. errif(listen(sockfd, SOMAXCONN) == -1, "socket listen error");
  17. struct sockaddr_in clnt_addr;
  18. socklen_t clnt_addr_len = sizeof(clnt_addr);
  19. bzero(&clnt_addr, sizeof(clnt_addr));
  20. int clnt_sockfd = accept(sockfd, (sockaddr*)&clnt_addr, &clnt_addr_len);
  21. errif(clnt_sockfd == -1, "socket accept error");
  22. printf("new client fd %d! IP: %s Port: %d\n", clnt_sockfd, inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port));
  23. while (true) {
  24. char buf[1024];
  25. bzero(&buf, sizeof(buf));
  26. ssize_t read_bytes = read(clnt_sockfd, buf, sizeof(buf));
  27. if(read_bytes > 0){
  28. printf("message from client fd %d: %s\n", clnt_sockfd, buf);
  29. write(clnt_sockfd, buf, sizeof(buf));
  30. } else if(read_bytes == 0){
  31. printf("client fd %d disconnected\n", clnt_sockfd);
  32. close(clnt_sockfd);
  33. break;
  34. } else if(read_bytes == -1){
  35. close(clnt_sockfd);
  36. errif(true, "socket read error");
  37. }
  38. }
  39. close(sockfd);
  40. return 0;
  41. }

client.cpp

  1. #include <iostream>
  2. #include <sys/socket.h>
  3. #include <arpa/inet.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include "util.h"
  7. int main() {
  8. int sockfd = socket(AF_INET, SOCK_STREAM, 0);
  9. errif(sockfd == -1, "socket create error");
  10. struct sockaddr_in serv_addr;
  11. bzero(&serv_addr, sizeof(serv_addr));
  12. serv_addr.sin_family = AF_INET;
  13. serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  14. serv_addr.sin_port = htons(8888);
  15. errif(connect(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)) == -1, "socket connect error");
  16. while(true){
  17. char buf[1024];
  18. bzero(&buf, sizeof(buf));
  19. scanf("%s", buf);
  20. ssize_t write_bytes = write(sockfd, buf, sizeof(buf));
  21. if(write_bytes == -1){
  22. printf("socket already disconnected, can't write any more!\n");
  23. break;
  24. }
  25. bzero(&buf, sizeof(buf));
  26. ssize_t read_bytes = read(sockfd, buf, sizeof(buf));
  27. if(read_bytes > 0){
  28. printf("message from server: %s\n", buf);
  29. }else if(read_bytes == 0){
  30. printf("server socket disconnected!\n");
  31. break;
  32. }else if(read_bytes == -1){
  33. close(sockfd);
  34. errif(true, "socket read error");
  35. }
  36. }
  37. close(sockfd);
  38. return 0;
  39. }

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

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

(3)高并发还得用epoll 

server.cpp

  1. #include <stdio.h>
  2. #include <sys/socket.h>
  3. #include <arpa/inet.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <fcntl.h>
  7. #include <sys/epoll.h>
  8. #include <errno.h>
  9. #include "util.h"
  10. #define MAX_EVENTS 1024
  11. #define READ_BUFFER 1024
  12. // 设置非阻塞
  13. void setnonblocking(int fd){
  14. // 设置文件的flags: fcntl(fd,F_SETFL,flags);
  15. fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
  16. }
  17. int main(){
  18. int sockfd = socket(AF_INET, SOCK_STREAM, 0);
  19. errif(sockfd == -1, "socket create error");
  20. struct sockaddr_in serv_addr;
  21. bzero(&serv_addr, sizeof(serv_addr));
  22. serv_addr.sin_family = AF_INET;
  23. serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  24. serv_addr.sin_port = htons(8888);
  25. errif(bind(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)) == -1, "socket bind error");
  26. errif(listen(sockfd, SOMAXCONN) == -1, "socket listen error");
  27. // 创建一个epoll文件描述符并返回,失败则返回-1
  28. int epfd = epoll_create1(0);
  29. errif(epfd == -1, "epoll create error");
  30. struct epoll_event events[MAX_EVENTS], ev;
  31. bzero(&events, sizeof(events));
  32. bzero(&ev, sizeof(ev));
  33. ev.data.fd = sockfd; // 该IO口为服务器socket fd(文件描述符)
  34. // EPOLLIN:LT模式,EPOLLET:ET模式
  35. ev.events = EPOLLIN; // 服务端最好不要用ET模式
  36. setnonblocking(sockfd);
  37. // 将服务器socket fd添加到epoll
  38. epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);
  39. while (1){
  40. // epoll_wait获取有事件发生的fd
  41. // 最大等待时间,设置为-1表示一直等待
  42. int nfds = epoll_wait(epfd, events, MAX_EVENTS, -1); // 有nfds个fd发生事件
  43. errif(nfds == -1, "epoll wait error");
  44. for(int i = 0; i < nfds; ++i){
  45. if(events[i].data.fd == sockfd){ // 发生事件的fd是服务器socket fd,表示有新客户端连接
  46. struct sockaddr_in clnt_addr;
  47. bzero(&clnt_addr, sizeof(clnt_addr));
  48. socklen_t clnt_addr_len = sizeof(clnt_addr);
  49. int clnt_sockfd = accept(sockfd, (sockaddr*)&clnt_addr, &clnt_addr_len);
  50. errif(clnt_sockfd == -1, "socket accept error");
  51. printf("new client fd %d! IP: %s Port: %d\n", clnt_sockfd, inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port));
  52. bzero(&ev, sizeof(ev));
  53. ev.data.fd = clnt_sockfd;
  54. ev.events = EPOLLIN | EPOLLET; // 对于客户端连接,使用ET模式,可以让epoll更加高效,支持更多并发
  55. setnonblocking(clnt_sockfd); // ET需要搭配非阻塞式socket使用
  56. epoll_ctl(epfd, EPOLL_CTL_ADD, clnt_sockfd, &ev);
  57. }else if (events[i].events & EPOLLIN){ // 发生事件的是客户端,并且是可读事件(EPOLLIN)
  58. char buf[READ_BUFFER];
  59. while(true){ //由于使用非阻塞IO,读取客户端buffer,一次读取buf大小数据,直到全部读取完毕
  60. bzero(&buf, sizeof(buf));
  61. ssize_t bytes_read = read(events[i].data.fd, buf, sizeof(buf));
  62. if(bytes_read > 0){
  63. // 保存读取到的bytes_read大小的数据
  64. printf("message from client fd %d: %s\n", events[i].data.fd, buf);
  65. write(events[i].data.fd, buf, sizeof(buf));
  66. }else if(bytes_read == -1 && errno == EINTR){ // 客户端正常中断、继续读取
  67. printf("continue reading");
  68. continue;
  69. }else if(bytes_read == -1 && ((errno == EAGAIN) || (errno == EWOULDBLOCK))){ // 非阻塞IO,这个条件表示数据全部读取完毕
  70. printf("finish reading once, errno: %d\n", errno);
  71. break;
  72. }else if(bytes_read == 0){ // EOF,客户端断开连接
  73. printf("EOF, client fd %d disconnected\n", events[i].data.fd);
  74. close(events[i].data.fd); // 关闭socket会自动将文件描述符从epoll树上移除
  75. break;
  76. }
  77. }
  78. }else{ //其他事件,之后的版本实现
  79. printf("something else happened\n");
  80. }
  81. }
  82. }
  83. close(sockfd);
  84. return 0;
  85. }

client.cpp

  1. #include <iostream>
  2. #include <sys/socket.h>
  3. #include <arpa/inet.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include "util.h"
  7. #define BUFFER_SIZE 1024
  8. int main(){
  9. int sockfd = socket(AF_INET, SOCK_STREAM, 0);
  10. errif(sockfd == -1, "socket create error");
  11. struct sockaddr_in serv_addr;
  12. bzero(&serv_addr, sizeof(serv_addr));
  13. serv_addr.sin_family = AF_INET;
  14. serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  15. serv_addr.sin_port = htons(8888);
  16. errif(connect(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)) == -1, "socket connect error");
  17. while (1){
  18. char buf[BUFFER_SIZE]; //在这个版本,buf大小必须大于或等于服务器端buf大小,不然会出错,想想为什么?
  19. bzero(&buf, sizeof(buf));
  20. scanf("%s", buf);
  21. ssize_t write_bytes = write(sockfd, buf, sizeof(buf));
  22. if(write_bytes == -1){
  23. printf("socket already disconnected, can't write any more!\n");
  24. break;
  25. }
  26. bzero(&buf, sizeof(buf));
  27. ssize_t read_bytes = read(sockfd, buf, sizeof(buf));
  28. if(read_bytes > 0){
  29. printf("message from server: %s\n", buf);
  30. }else if(read_bytes == 0){
  31. printf("server socket disconnected!\n");
  32. break;
  33. }else if(read_bytes == -1){
  34. close(sockfd);
  35. errif(true, "socket read error");
  36. }
  37. }
  38. close(sockfd);
  39. return 0;
  40. }

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

InetAddress.h

  1. #pragma once
  2. #include <iostream>
  3. #include <arpa/inet.h>
  4. class InetAddress{
  5. public:
  6. InetAddress();
  7. InetAddress(std::string ip, uint16_t port);
  8. struct sockaddr_in getAddr(){
  9. return addr;
  10. }
  11. socklen_t getAddrLen(){
  12. return addr_len;
  13. }
  14. private:
  15. struct sockaddr_in addr;
  16. socklen_t addr_len;
  17. };

 InetAddress.cpp

  1. #include <iostream>
  2. #include<string.h>
  3. #include "InetAddress.h"
  4. InetAddress::InetAddress() : addr_len(sizeof(addr)){
  5. bzero(&addr, sizeof(addr));
  6. }
  7. InetAddress::InetAddress(std::string ip, uint16_t port) : addr_len(sizeof(addr)){
  8. bzero(&addr, sizeof(addr));
  9. addr.sin_family = AF_INET;
  10. addr.sin_addr.s_addr = inet_addr(ip.c_str());
  11. addr.sin_port = htons(port);
  12. }

Socket.h

  1. #pragma once
  2. #include <iostream>
  3. #include <tr1/memory>
  4. #include "InetAddress.h"
  5. class Socket{
  6. public:
  7. Socket();
  8. Socket(int);
  9. ~Socket();
  10. void bind(InetAddress*);
  11. void listen();
  12. void setnonblocking();
  13. int accept(InetAddress*);
  14. int getFd();
  15. private:
  16. int fd; // 文件描述符
  17. };

 Socket.cpp

  1. #include "Socket.h"
  2. #include "InetAddress.h"
  3. #include "util.h"
  4. #include <unistd.h>
  5. #include <fcntl.h>
  6. #include <sys/socket.h>
  7. #include <iostream>
  8. #include <tr1/memory>
  9. Socket::Socket() : fd(-1){
  10. fd = socket(AF_INET, SOCK_STREAM, 0);
  11. errif(fd == -1, "socket create error");
  12. }
  13. Socket::Socket(int fd_) : fd(fd_){
  14. errif(fd == -1, "socket create error");
  15. }
  16. Socket::~Socket(){
  17. if(fd != -1){
  18. close(fd);
  19. fd = -1;
  20. }
  21. }
  22. void Socket::bind(InetAddress *addr){
  23. struct sockaddr_in addrTmp = addr->getAddr();
  24. socklen_t addrLen = addr->getAddrLen();
  25. errif(::bind(fd, (sockaddr*)&addrTmp, addrLen) == -1, "socket bind error");
  26. }
  27. void Socket::listen(){
  28. errif(::listen(fd, SOMAXCONN) == -1, "socket listen error");
  29. }
  30. void Socket::setnonblocking(){
  31. fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
  32. }
  33. int Socket::accept(InetAddress *addr){
  34. struct sockaddr_in addrTmp = addr->getAddr();
  35. socklen_t addrLen = addr->getAddrLen();
  36. int clnt_sockfd = ::accept(fd, (sockaddr*)&addrTmp, &addrLen);
  37. errif(clnt_sockfd == -1, "socket accept error");
  38. return clnt_sockfd;
  39. }
  40. int Socket::getFd(){
  41. return fd;
  42. }

Epoll.h

  1. #pragma once
  2. #include <sys/epoll.h>
  3. #include <iostream>
  4. #include <vector>
  5. class Epoll{
  6. public:
  7. Epoll();
  8. ~Epoll();
  9. void addFd(int fd, uint32_t op);
  10. std::vector<epoll_event> poll(int timeout = -1);
  11. private:
  12. int epfd;
  13. epoll_event* events;
  14. };

 Epoll.cpp

  1. #include "Epoll.h"
  2. #include "util.h"
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <iostream>
  6. #define MAX_EVENTS 1000
  7. Epoll::Epoll() : epfd(-1), events(nullptr){
  8. epfd = epoll_create1(0);
  9. errif(epfd == -1, "epoll create error");
  10. events = new epoll_event[MAX_EVENTS];
  11. bzero(events, sizeof(*events) * MAX_EVENTS);
  12. }
  13. Epoll::~Epoll(){
  14. if(epfd != -1){
  15. close(epfd);
  16. epfd = -1;
  17. }
  18. delete[] events; // 防止内存泄漏
  19. }
  20. void Epoll::addFd(int fd, uint32_t op){
  21. struct epoll_event ev;
  22. bzero(&ev, sizeof(ev));
  23. ev.data.fd = fd;
  24. ev.events = op;
  25. errif(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1, "epoll add event error");
  26. }
  27. std::vector<epoll_event> Epoll::poll(int timeout){
  28. std::vector<epoll_event> activeEvents;
  29. int nfds = epoll_wait(epfd, events, MAX_EVENTS, timeout);
  30. errif(nfds == -1, "epoll wait error");
  31. for(int i = 0; i < nfds; ++i){
  32. activeEvents.push_back(events[i]);
  33. }
  34. return activeEvents;
  35. }

server.cpp

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <unistd.h>
  4. #include <fcntl.h>
  5. #include <errno.h>
  6. #include <vector>
  7. #include "util.h"
  8. #include "Epoll.h"
  9. #include "InetAddress.h"
  10. #include "Socket.h"
  11. #include <iostream>
  12. #define MAX_EVENTS 1024
  13. #define READ_BUFFER 1024
  14. void setnonblocking(int fd){
  15. fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
  16. }
  17. void handleReadEvent(int);
  18. int main() {
  19. Socket *serv_sock = new Socket();
  20. InetAddress *serv_addr = new InetAddress("127.0.0.1", 8888);
  21. serv_sock->bind(serv_addr);
  22. serv_sock->listen();
  23. Epoll *ep = new Epoll();
  24. serv_sock->setnonblocking();
  25. ep->addFd(serv_sock->getFd(), EPOLLIN | EPOLLET);
  26. while(true){
  27. std::vector<epoll_event> events = ep->poll();
  28. int nfds = events.size();
  29. for(int i = 0; i < nfds; ++i){
  30. if(events[i].data.fd == serv_sock->getFd()){ // 新客户端连接
  31. // new InetAddress() 位置只能在这里!
  32. InetAddress *clnt_addr = new InetAddress();
  33. Socket *clnt_sock = new Socket(serv_sock->accept(clnt_addr));
  34. printf("new client fd %d! IP: %s Port: %d\n", clnt_sock->getFd(),
  35. inet_ntoa(clnt_addr->getAddr().sin_addr), ntohs(clnt_addr->getAddr().sin_port));
  36. clnt_sock->setnonblocking();
  37. ep->addFd(clnt_sock->getFd(), EPOLLIN | EPOLLET);
  38. } else if(events[i].events & EPOLLIN){ // 可读事件
  39. handleReadEvent(events[i].data.fd);
  40. } else{ // 其他事件,之后的版本实现
  41. printf("something else happened\n");
  42. }
  43. }
  44. }
  45. delete serv_sock;
  46. delete serv_addr;
  47. delete ep;
  48. return 0;
  49. }
  50. void handleReadEvent(int sockfd){
  51. char buf[READ_BUFFER];
  52. while (1){ // 由于使用非阻塞IO,读取客户端buffer,一次读取buf大小数据,直到全部读取完毕
  53. bzero(&buf, sizeof(buf));
  54. ssize_t bytes_read = read(sockfd, buf, sizeof(buf));
  55. if(bytes_read > 0){
  56. printf("message from client fd %d: %s\n", sockfd, buf);
  57. write(sockfd, buf, sizeof(buf));
  58. } else if(bytes_read == -1 && errno == EINTR){ // 客户端正常中断、继续读取
  59. printf("continue reading");
  60. continue;
  61. } else if(bytes_read == -1 && ((errno == EAGAIN) || (errno == EWOULDBLOCK))){ // 非阻塞IO,这个条件表示数据全部读取完毕
  62. printf("finish reading once, errno: %d\n", errno);
  63. break;
  64. } else if(bytes_read == 0){ // EOF,客户端断开连接
  65. printf("EOF, client fd %d disconnected\n", sockfd);
  66. close(sockfd); // 关闭socket会自动将文件描述符从epoll树上移除
  67. break;
  68. }
  69. }
  70. }

client.cpp

  1. #include <iostream>
  2. #include <sys/socket.h>
  3. #include <arpa/inet.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include "util.h"
  7. #define BUFFER_SIZE 1024
  8. int main(){
  9. int sockfd = socket(AF_INET, SOCK_STREAM, 0);
  10. errif(sockfd == -1, "socket create error");
  11. struct sockaddr_in serv_addr;
  12. bzero(&serv_addr, sizeof(serv_addr));
  13. serv_addr.sin_family = AF_INET;
  14. serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  15. serv_addr.sin_port = htons(8888);
  16. errif(connect(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)) == -1, "socket connect error");
  17. while (1){
  18. char buf[BUFFER_SIZE]; //在这个版本,buf大小必须大于或等于服务器端buf大小,不然会出错,想想为什么?
  19. bzero(&buf, sizeof(buf));
  20. scanf("%s", buf);
  21. ssize_t write_bytes = write(sockfd, buf, sizeof(buf));
  22. if(write_bytes == -1){
  23. printf("socket already disconnected, can't write any more!\n");
  24. break;
  25. }
  26. bzero(&buf, sizeof(buf));
  27. ssize_t read_bytes = read(sockfd, buf, sizeof(buf));
  28. if(read_bytes > 0){
  29. printf("message from server: %s\n", buf);
  30. }else if(read_bytes == 0){
  31. printf("server socket disconnected!\n");
  32. break;
  33. }else if(read_bytes == -1){
  34. close(sockfd);
  35. errif(true, "socket read error");
  36. }
  37. }
  38. close(sockfd);
  39. return 0;
  40. }
  1. g++ util.cpp client.cpp -o client && \
  2. 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,及一些默认的属性,如日志格式、日志写入等级。

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/51352
推荐阅读
相关标签
  

闽ICP备14008679号