C++ 设计模式

文章目录

  • 类图
    • 泛化
    • 实现
    • 关联
    • 聚合
    • 组合
    • 依赖
    • 总结
  • 类内部的三种权限(公有、保护、私有)
  • 类的三种继承方式
    • 描述与图
    • 总结
  • 面向对象七大原则
    • 单一职责原则(Single Responsibility Principle)
    • 里氏替换原则(Liskov Substitution Principle)
    • 依赖倒置原则(Dependence Inversion Principle)
    • 接口隔离原则(Interface Segregation Principle)
    • 迪米特法则(Law Of Demeter)
    • 开闭原则(Open Close Principle)
    • 组合/聚合复用原则(Composite/Aggregate Reuse Principle CARP)
  • 关于类的静态成员
  • 类的静态成员函数
  • 关于C++构造函数的继承问题
  • C++虚函数
  • 个人总结
  • 创建型模式
    • Factory模式(工厂模式)
    • AbstractFactory模式(抽象工厂模式)

类图

泛化

  • 【泛化】是一种继承关系,表示一般与特殊的关系,它指定了子类如何继承父类的所有特征和行为。例如:老虎是动物的一种,即有老虎的特性也有动物的共性。
  • 【代码体现】:继承。
  • 特征:空白三角形+实线 指向父类
    动物是老虎的父类

实现

  • 【实现关系】是一种类与接口的关系,表示类是接口所有特征和行为的实现。

  • 特征:空白三角形箭头+虚线 箭头指向接口
    在这里插入图片描述

  • 【代码体现】:纯虚函数

  • 对于C++,其接口类一般具有以下特征:

    • 最好不要有成员变量,但可以有静态常量(static const或enum)
      • 如果成员变量,尤其是可变的成员变量,定义在接口中,等于是把实现细节暴露出来了,不符合接口定义的要求,所以一般不在接口中定义可变的成员变量。
        而常量可以定义在接口中,因为有时接口需要返回状态,而这些状态可以定义成常量放在接口中。
    • 要有纯虚接口方法
      • 由于不能让接口类自身能够实例化,并且需要子类必须实现接口暴露的方法,所以接口方法都要声明成纯虚函数。
        声明成纯虚函数意味着接口类自身不需要提供方法的定义,方法的定义需要由接口类的子类提供,并且接口类自身也因此变成了抽象类而不能被实例化。
    • 要有虚析构函数,并提供默认实现
      • 在使用接口类的指针访问接口类的子类的实例时,当对接口类的指针做delete时,如果接口类的析构函数不是虚析构函数的话,将只会调用接口类(父类)的析构函数,接口类的子类的析构函数将不会被调用,内存泄露将会产生,所以接口类的析构函数必须定义成虚析构函数。
      • 如果接口类的析构函数不提供默认实现,即如果接口类的析构函数是纯虚析构函数的话,接口类的子类将被迫必须提供析构函数的实现,这样对接口类的子类不友好。
    • 不要声明构造函数
      • 不要显式定义任何的构造函数,但也不要在接口中加入如下代码来禁止生成构造函数:
      • Testable() = delete; Testable(const Testable&) = delete;
      • 因为C++的调用机制要求子类的构造函数调用时一定会先调用父类的构造函数,如果禁止生成父类构造函数,代码编译时会报错。如果程序员不显式的提供构造函数,编译器也会隐式的加上构造函数的,虽然这些构造函数对于接口类来说实际没有什么意义。
    • 例子:
class Testable
{
public:static const int START = 1;  // #1static const int STOP = 2;virtual void test() = 0;  // #2: 接口方法virtual ~Testable() {};   // #3: 从C++11开始可以: virtual ~Testable() = default;
}

关联

  • 【关联关系】是一种拥有的关系,它使一个类知道另一个类的属性和方法;如:老师与学生,丈夫与妻子关联可以是双向的,也可以是单向的。双向的关联可以有两个箭头或者没有箭头,单向的关联有一个箭头。
  • 【代码体现】:成员变量
  • 特征:实线 n n实线 1 n 箭头指向被拥有者
    在这里插入图片描述
  • 上图中,老师与学生是双向关联,老师有多名学生,学生也可能有多名老师。但学生与某课程间的关系为单向关联,一名学生可能要上多门课程,课程是个抽象的东西他不拥有学生。

聚合

  • 【聚合关系】:是整体与部分的关系,且部分可以离开整体而单独存在。如车和轮胎是整体和部分的关系,轮胎离开车仍然可以存在。
  • 【聚合关系】是关联关系的一种,是强的关联关系;关联和聚合在语法上无法区分,必须考察具体的逻辑关系。
  • 特征:菱形+实线+箭头在这里插入图片描述

组合

  • 【组合关系】:是整体与部分的关系,但部分不能离开整体而单独存在。如公司和部门是整体和部分的关系,没有公司就不存在部门

  • 组合关系是关联关系的一种,是比聚合关系还要强的关系,它要求普通的聚合关系中代表整体的对象负责代表部分的对象的生命周期。
    在这里插入图片描述

依赖

  • 【依赖关系】:是一种使用的关系,即一个类的实现需要另一个类的协助,所以要尽量不使用双向的互相依赖.
  • 【代码表现】:局部变量、方法的参数、对静态方法的调用、函数返回值
  • 【箭头及指向】:带箭头的虚线,指向被使用者。
    在这里插入图片描述

总结

各种关系的强弱顺序:
泛化 = 实现 > 组合 > 聚合 > 关联 > 依赖
下面这张UML图,比较形象地展示了各种类图关系:
在这里插入图片描述

类内部的三种权限(公有、保护、私有)

在这里插入图片描述
权限按照以下两点递减:

  • 是否能被外部访问
  • 是否能被继承的子类访问

类的三种继承方式

描述与图

  • public继承方式
    基类中所有 public 成员在派生类中为 public 属性;
    基类中所有 protected 成员在派生类中为 protected 属性;
    基类中所有 private 成员在派生类中不能使用。

  • protected继承方式
    基类中的所有 public 成员在派生类中为 protected 属性;
    基类中的所有 protected 成员在派生类中为 protected 属性;
    基类中的所有 private 成员在派生类中不能使用。

  • private继承方式
    基类中的所有 public 成员在派生类中均为 private 属性
    基类中的所有 protected 成员在派生类中均为 private 属性
    基类中的所有 private 成员在派生类中不能使用。

继承方式/基类成员public成员protected成员private成员
public继承publicprotected不可见
protected继承protectedprotected不可见
private继承privateprivate不可见

总结

  • 父类的private成员在子类不能使用、不可见
  • 父类的成员在子类中的权限,最高为其子类的继承方式。

面向对象七大原则

单一职责原则(Single Responsibility Principle)

  • 每一个类应该专注于做一件事情
  • 可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多;提高类的可读性,提高系统的可维护性;变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。需要说明的一点是单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都适用单一职责原则。

里氏替换原则(Liskov Substitution Principle)

  • 子类对象能够替换程序中父类对象出现的任何地方,并且保证原来程序的逻辑行为不变及正确性不被破坏
  • 使用里氏替换原则时需要注意,子类的所有方法必须在父类中声明,或子类必须实现父类中声明的所有方法。尽量把父类设计为抽象类或者接口,让子类继承父类或实现父接口,并实现在父类中声明的方法,运行时,子类实例替换父类实例,我们可以很方便地扩展系统的功能,同时无须修改原有子类的代码,增加新的功能可以通过增加一个新的子类来实现。

依赖倒置原则(Dependence Inversion Principle)

  • 程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。
  • 面向抽象编程,也就是面向抽象类或接口编程。

接口隔离原则(Interface Segregation Principle)

应当为客户端提供尽可能小的单独的接口,而不是提供大的总的接口。

迪米特法则(Law Of Demeter)

又叫最少知识原则,一个软件实体应当尽可能少的与其他实体发生相互作用。

开闭原则(Open Close Principle)

面向扩展开放,面向修改关闭。

组合/聚合复用原则(Composite/Aggregate Reuse Principle CARP)

尽量使用合成/聚合达到复用,尽量少用继承。原则: 一个类中有另一个类的对象。

关于类的静态成员

  • 类的静态成员与类本身直接相关而不是与类的各个对象保持关联

  • 我们不能在类的内部初始化静态数据成员必须在类的外部初始化
    在这里插入图片描述
    在这里插入图片描述

  • 字面值常量类型constexpr除外
    在这里插入图片描述

类的静态成员函数

在这里插入图片描述

/*类静态成员、静态成员函数例子如下*/
#include <iostream>
#include <cstdio>
#include <cstring>using namespace std;class Guest{
private:static int m_num;static int m_count;static double m_totalFee;string name;int num;double fee;
public:Guest(string name, double fee):name(name),fee(fee){m_num++;num = m_num;m_count++;m_totalFee+=fee;}~Guest(){m_count--;}void show() const{printf("num:%d,name:%s,fee:%.2lf\n",num,name.c_str(),fee);}static int GetCount(){return m_count;}static double GetTotalIncome(){return m_totalFee;}
};int Guest::m_num = 0;
int Guest::m_count = 0;
double Guest::m_totalFee = 0;int main(int argc, char *argv[])
{Guest g1("lihua",11.99), g2("zhangsan",12.99), g3("xiaomei",13.99);g1.show();g2.show();g3.show();printf("count:%d,totalFee:%.2f\n",Guest::GetCount(),Guest::GetTotalIncome());return 0;
}

关于C++构造函数的继承问题

  • 构造方法用来初始化类的对象,与父类的其它成员不同,它不能被子类继承子类可以继承父类所有的成员变量和成员方法,但不继承父类的构造方法)。因此,在创建子类对象时,为了初始化从父类继承来的数据成员,子类需要调用其父类的构造方法
  • 如果没有显式的构造函数,编译器会给一个默认的构造函数,并且该默认的构造函数仅仅在没有显式地声明构造函数情况下创建
  • 如果子类调用父类带参数的构造方法,需要用初始化父类成员对象的方式
#include <iostream.h>  class animal  {  public:  animal(int height, int weight)   //有且仅有 有参参数,必须显性调用{  cout<<"animal construct"<<endl;  }};  class fish:public animal  {  public:  fish():animal(400,300)  {  cout<<"fish construct"<<endl;  }};  void main()  {  fish fh;  }  
  • 在fish类的构造函数后,加一个冒号(:),然后加上父类的带参数的构造函数。这样,在子类的构造函数被调用时,子类就会去调用父类的带参数的构造函数去构造对象

C++虚函数

传送门

个人总结

  • 继承时,父类的构造函数和析构函数不会被子类继承,但会在子类调用构造函数前和子类调用析构函数后调用。顺序如下:父类构造函数,子类构造函数。 子类析构函数,父类析构函数。(想象建造一座楼,父类在下,子类在上。从下往上建,从上往下拆)
  • 假设有父类Shape,子类Circle,调用如下代码
	Shape *a = new Circle();delete a;

在这里插入图片描述

new Circle()时,将会调用Circle(子类)的构造函数,delete a时,由于指针a是基类,将只会调用父类的析构函数,所以我们必须实现多态(用虚函数),使得对象为Circle时,delete会调用子类的析构函数。方法是将析构函数声明为虚函数

  • 声明虚函数时,每个类会有一个虚函数表,子类继承父类时,会覆盖父类的虚函数表的函数指针。若一个函数是虚函数,则会去虚函数表里找到函数指针来去实现它。

创建型模式

Factory模式(工厂模式)

在这里插入图片描述

//Product.h
#ifndef _PRODUCT_H_
#define _PRODUCT_H_
class Product
{
public:virtual ~Product() = 0; //多态时,调用子类的析构函数
protected:Product();     //不可被外部调用,抽象基类不可以被实例化
private:
};class ConcreteProduct:public Product
{
public:~ConcreteProduct();ConcreteProduct();
protected:
private:
};
#endif
//Product.cpp
#include "Product.h"
#include <iostream>
Product::Product()
{std::cout<<"Product()...."<<std::endl; 
}Product::~Product()
{std::cout<<"~Product()...."<<std::endl; 
}ConcreteProduct::ConcreteProduct()
{std::cout<<"ConcreteProduct()...."<<std::endl; 
}ConcreteProduct::~ConcreteProduct()
{std::cout<<"~ConcreteProduct()...."<<std::endl; 
}
//Factory.h
#ifndef _FACTORY_H_
#define _FACTORY_H_
class Product;
//factory抽象基类
class Factory   
{
public:virtual ~Factory() = 0;         //析构函數virtual Product* CreateProduct() = 0;   
protected:Factory();      //构造函数,外部不可以调用,子类可以调用
private:
};//factory实例
class ConcreteFactory:public Factory
{
public:~ConcreteFactory();         ConcreteFactory();Product* CreateProduct();
protected:
private:
};
#endif
//Factory.cpp
#include "Product.h"
#include "Factory.h"
#include <iostream>Factory::Factory()
{std::cout<<"Factory()...."<<std::endl; 
}Factory::~Factory()
{std::cout<<"~Factory()...."<<std::endl; 
}ConcreteFactory::ConcreteFactory()
{std::cout<<"ConcreteFactory()......"<<std::endl;
}ConcreteFactory::~ConcreteFactory()
{std::cout<<"~ConcreteFactory()......"<<std::endl;
}Product* ConcreteFactory::CreateProduct()
{return new ConcreteProduct();
}
//main.cpp
#include "Factory.h"
#include "Product.h"
#include <iostream>
#include <cstdio>
int main(int argc, char* argv[])
{Factory *fac = new ConcreteFactory();Product* p = fac->CreateProduct();delete p;delete fac;return 0;
}
#makefile
CC = g++ -g
BaseIncludePath = ../include/
SRCS = main.cpp Product.cpp Factory.cpp
OBJS = $(addsuffix .o,$(basename ${SRCS}))main.exe: $(OBJS)$(CC) $(OBJS) -o main.exe %.o: %.cpp$(CC) -c $< -o $@ -I$(BaseIncludePath)clean:del $(OBJS) main.exe

AbstractFactory模式(抽象工厂模式)

在这里插入图片描述

  • 抽象工厂模式和工厂方法模式一样,都符合开闭原则。但是不同的是,在抽象工厂模式中,增加一个产品族很容易,而增加一个产品等级结构却很难,工厂模式则反之。

  • 也就是说,在抽象工厂模式中,增加一个具体的工厂很容易,但是你想在工厂中多生产一种产品,就需要修改很多个类,会违背开闭原则,这种情况下应该使用工厂模式。

  • 简单来说:工厂模式新增产品类型容易,抽象工厂模式新增工厂类型容易

表头表头
单元格单元格
单元格单元格

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/268370.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

笔记本hp6930p安装Android-x86补记

在上一篇日记中&#xff08;笔记本hp6930p安装Android-x86避坑日记-CSDN博客&#xff09;提到hp6930p安装Android-x86-9.0&#xff0c;无法正常启动&#xff0c;本文对此再做尝试&#xff0c;原因是&#xff1a;Android-x86-9.0不支持无线网卡&#xff0c;需要在BIOS中关闭WLAN…

2024.3.1 网络编程

1.思维导图 2.TCP机械臂测试 程序代码&#xff1a; #include <myhead.h> #define SER_IP "192.168.125.254" //服务器端IP #define SER_PORT 8888 //服务器端端口号#define CLI_IP "192.168.199.131" //客户端IP …

在Arcgis中删除过滤Openstreetmap道路属性表中指定highway类型道路

一、导出道路类型并分析 1. 导出道路类型 选中highway属性列&#xff0c;选择汇总→确定 2. 分析 用Excel打开输出表&#xff0c;包含的道路类型如下 0.空值’’ 车辆可行驶道路&#xff08;和bfmap的并集&#xff09; 空值&#xff08;无定义道路&#xff09; 二、…

MySQL数据库运维第一篇(日志与主从复制)

文章目录 一、错误日志二、二进制日志三、查询日志四、慢查询日志&#xff08;记录超时的sql语句&#xff09;五、主从复制概括六、主从复制原理七、搭建主从复制八、主从复制的测试 在这篇深入的技术文章中&#xff0c;作者将以明晰透彻的方式详细介绍MySQL数据库中关键的日志…

【风格迁移】对比度保持连贯性损失 CCPL:解决图像局部失真、视频帧间的连贯性和闪烁

对比度保持连贯性损失 CCPL&#xff1a;解决图像局部失真、视频帧间的连贯性和闪烁 提出背景解法&#xff1a;对比度保持连贯性损失&#xff08;CCPL&#xff09; 局部一致性假设 对比学习机制 邻域调节策略 互信息最大化对比学习&#xff1a;在无需标签的情况下有效学习区分…

源码视角,vue3为什么推荐用ref,而不是reactive

ref 和 reactive 是 Vue3 中实现响应式数据的核心 API。ref 用于包装基本数据类型&#xff0c;而 reactive 用于处理对象和数组。尽管 reactive 似乎更适合处理对象&#xff0c;但 Vue3 官方文档更推荐使用 ref。 我的想法&#xff0c;ref就是比reactive好用&#xff0c;官方也…

深入理解nginx的https sni机制

目录 1. 概述2. 初识sni3. nginx的ssl证书配置指令3.1 ssl_certificate3.2 ssl_certificate_key3.3 ssl_password_file4. nginx源码分析4.1 给ssl上下文的初始化4.2 连接初始化4.3 处理sni回调4.2 动态证书的加载5. 总结阅读姊妹篇: 深入理解nginx的https alpn机制 1. 概述 SN…

[BJDCTF2020]EzPHP1 --不会编程的崽

有一说一&#xff0c;这题还是有难度的 base32解码url编码绕过$_SERVER换行符绕过preg_match相同参数&#xff0c;post请求覆盖get请求&#xff0c;绕过$_REQUESTphp伪协议利用sha1数组绕过create_function代码注入 Level 1 右键源码里又发现&#xff0c;拿去base32解码即可…

【Java项目介绍和界面搭建】拼图小游戏——键盘、鼠标事件

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏 …

【go从入门到精通】go包,内置类型和初始化顺序

大家好&#xff0c;这是我给大家准备的新的一期专栏&#xff0c;专门讲golang&#xff0c;从入门到精通各种框架和中间件&#xff0c;工具类库&#xff0c;希望对go有兴趣的同学可以订阅此专栏。 go基础 。 Go文件名&#xff1a; 所有的go源码都是以 ".go" 结尾&…

【大厂AI课学习笔记NO.62】模型的部署

我们历尽千辛万苦&#xff0c;总算要部署模型了。这个系列也写到62篇&#xff0c;不要着急&#xff0c;后面还有很多。 这周偷懒了&#xff0c;一天放出太多的文章&#xff0c;大家可能有些吃不消&#xff0c;从下周开始&#xff0c;本系列将正常更新。 这套大厂AI课&#xf…

C++_红黑树

目录 1、红黑树的规则 2、红黑树节点的定义 3、红黑树插入节点的调整操作 3.1 情况一 3.2 情况二 3.3 情况三 4、红黑树的实现 结语 前言&#xff1a; 在C中&#xff0c;红黑树是二叉搜索树的另一种优化版本&#xff0c;他与AVL树的区别在于保持树的平衡方式不同&…

django的模板渲染中的【高级定制】:按数据下标id来提取数据

需求&#xff1a; 1&#xff1a;在一个页面中显示一张数据表的数据 2&#xff1a;不能使用遍历的方式 3&#xff1a;页面中的数据允许通过admin后台来进行修改 4&#xff1a;把一张数据表的某些内容渲染到[xxx.html]页面 5&#xff1a;如公司的新商品页面&#xff0c;已有固定的…

波斯猫 6页面 宠物动物 长毛猫 HTML5 带背景音乐 JS图片轮播特效 滚动文字 鼠标经过图片 JS时间代码

波斯猫 6页面 宠物动物 长毛猫 HTML5 带背景音乐 JS图片轮播特效 滚动文字 鼠标经过图片 JS时间代码 注册表单 宠物网页成品 海量学生网页成品 个人博客 人物明星 城市家乡 旅游景点 美食特产 购物电商 公司企业 学校大学 科普教育 宠物动物 鲜花花卉 植物水果 茶叶咖啡 健康生…

react native封装ScrollView,实现(滑到底部)和(滑到顶部+手指继续向下滑)时拉取新数据

里面的tw是在react native中使用tailwind的第三方库 只求读者把样式看个大概&#xff0c;主要还是功能的实现 ScrollView的官方文档如下 https://reactnative.cn/docs/scrollview import tw from twrnc import { View, Text, ScrollView, RefreshControl } from react-native …

Python用类实现抽象和封装

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 路在脚下&#xff0c;勇往直前&#x…

Git——Upload your open store

0.default config ssh-keygen -t rsa #之后一路回车,当前目录.ssh/下产生公私钥 cat ~/.ssh/id_rsa.pub #复制公钥到账号 git config --global user.email account_email git config --global user.name account_name1. 上传一个公开仓库 查看当前分支&#xff1a; git branc…

去中心化时代,品牌如何赢得确定性增长

去中心化时代下&#xff0c;品牌面临众多挑战。在如今复杂的环境下&#xff0c;有很多不确定的因素&#xff0c;流量、资本等等&#xff0c;这些都是品牌发展过程中的不确定因素&#xff0c;越是复杂的环境下&#xff0c;品牌越要保证自己核心优势&#xff0c;找到并放大我们的…

华为配置攻击检测功能示例

配置攻击检测功能示例 组网图形 图1 配置攻击检测功能示例组网图 业务需求组网需求数据规划配置思路配置注意事项操作步骤配置文件 业务需求 企业用户通过WLAN接入网络&#xff0c;以满足移动办公的最基本需求。且在覆盖区域内移动发生漫游时&#xff0c;不影响用户的业务使用。…

AI大预言模型——ChatGPT与AI绘图及论文高效写作

原文链接&#xff1a;AI大预言模型——ChatGPT与AI绘图及论文高效写作 2023年随着OpenAI开发者大会的召开&#xff0c;最重磅更新当属GPTs&#xff0c;多模态API&#xff0c;未来自定义专属的GPT。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义&#xff0c;不亚于互联网…