一、类和对象的重要知识点

1.1 深拷贝与浅拷贝

浅拷贝:简单的赋值拷贝操作,拷贝构造
深拷贝:在堆区重新申请空间,进行拷贝操作

1.2 this指针

this指针指向被调用的成员函数所属的对象。
本质是指针常量(即指针的指向是不可以修改的,但指向的内容的值是可以修改的)

用途

  1. 当形参和成员变量同名时,可用this指针来区分

  2. 在类的非静态成员函数中返回对象本身,可使用 return * this 返回该对象的引用,达到链式编程

1.3 const修饰成员函数

常函数:

  1. 成员函数后加const,称这个函数为常函数,本质上是 修饰this指针指向,让指针指向的内容值也不可以修改. eg: 返回值 函数名() const

  2. 一般常函数内不可以修改成员属性

  3. 成员属性声明时加关键字mutable后,在常函数中依然可以修改

常对象:

  1. 声明对象前加const,称该对象为常对象 eg: const Object obj;

  2. 常对象只能调用常函数。

实践

#include <iostream>using namespace std;class temp{public:temp(){this->k = 10;}
//    void setValue(int k) const{ //函数后面加上const表示该函数中不可以修改成员变量的值
//          this->k = k;
//      }void setValue(int k) const{ //但是变量申明伟mutable 可以改变this->k = k;}int getValue() const{return this->k;}private:mutable int k;
};int main(void) {temp t;temp *p = &t;cout<< "t.getValue()="<<t.getValue()<<endl;//“.”是成员运算符,用于调取成员变量和成员函数cout<< "p->getValue()="<<p->getValue()<<endl;//“->”是地址运算符,用于引用成员变量和成员函数;return 0;
}

1.4 友元

目的是让一个函数或者类,访问另一个类中私有成员
友元用关键字 friend表示
友元的三种实现

  1. 全局函数做友元

  2. 类做友元

  3. 成员函数做友元

实践

#include <iostream>using namespace std;class temp{friend int main(void) ;//声明该函数为友元函数public:temp(){this->k = 10;}int getValue() const{return this->k;}private:void setValue(int k) { this->k = k;}int k;
};int main(void) {temp t;cout<< "t.getValue()="<<t.getValue()<<endl;t.setValue(100);// 由于setValue是私有函数,如果正常情况类外部是无法访问的,通过在类中声明该函数为友元函数访问cout<< "t.getValue()="<<t.getValue()<<endl;return 0;
}

二、运算符重载

operator@
运算符重载(operator overloading)只是一种“语法上的方便”,它只是另一种函数调用的方式,本质上是函数(成员函数或者全局函数),简化省略operator后就是运算符重载的语法糖效果。

运算符重载有两种方式:

  1. 成员函数

  2. 全局函数
    运算符重载 也可以发生函数重载
    对于内置的数据的类型的运算符无法改变,只可用于用户自定义类型。
    不要滥用运算符重载
    常用的运算符重载 “+”、“<<”、“++”、“=” “< > != ==”

下面以重载”+”运算符,实现两个对象相加。

#include <iostream>using namespace std;class temp{public:temp(){this->k = 10;this->t = 100;}int k;int t;
};temp operator+(temp param1,temp param2){temp a;a.k = param1.k+param2.k;a.t = param1.t+param2.t;return a;
}int main(void) {temp t1;temp t2;cout<<(t1+t2).k<<endl;cout<<(t1+t2).t<<endl;return 0;
}

关注+后台私信我,领取2022最新最全学习提升资料包+面试题+学习视频,内容包括(C/C++,Linux,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)等等

三、继承

单继承时派生类的定义
语法

class 派生类名:继承方式 基类名
{成员声明;
}多继承时派生类的定义
语法
class 派生类名:继承方式1 基类名1,继承方式2 基类名2,...
{成员声明;
}

有三种继承方式:共有继承;私有继承;保护继承

CPP允许多继承,但是实际开发中不建议使用多继承,因为父类中可能出现重名的属性或方法,需要加作用域区分。
菱形继承 可以采用虚函数虚继承的方式解决,即晚捆绑,这个我们在下一小节多态中再具体看。

通过sizeof查看父类和子类,父类的私有成员在子类中仍然占用存储空间,只不过不可以直接访问。

四、多态

多态性(Polymorphism)提供了接口与具体实现之间额一层隔离,改善了代码的组织结构和可读性,利于前后期的维护及扩展

动态多态满足条件

  1. 有继承关系

  2. 子类重写父类的虚函数

动态多态的场景:当父类的指针或者引用指向子类对象时,就发生了动态多态。

地址早绑定,在编译阶段确定了函数地址。
使用visual虚函数关键字告诉编译器,这个函数地址不能提前绑定,需要在运行阶段进行绑定,

加入virtual后编译器会分配一个指针 vfptr:virtual function pointer
vftable:virtual function table 记录虚函数地址。

当子类重写父类的虚函数
子类的虚函数表内部会替换成子类的虚函数地址

函数调用捆绑

把函数体与函数调用相联系称为捆绑(binding)。当捆绑在程序运行之前(有编译器和连接器)完成时,成为早捆绑(early biding)。在运行时才能确定捆绑类型成为晚捆绑(late dbinding)。
对于特定的函数,为了引起晚捆绑,CPP要求在基类中声明这个函数时使用virtual关键字。为了创建一个virtual成员函数,可以简单地在这个函数声明的前面加上关键字virtual,仅仅在声明的使用需要使用关键值virtual,定义时不需要。如果一个函数在基类中被声明为virtual,那么所有的派生类中它都是virtual。

纯虚函数与抽象类
在设计时,比较已扩展性的设计时基类仅仅作为其派生类的一个接口,即不希望用户创建一个基类对象。要做到这一点,可以在基类中加入至少一个纯虚函数(pure virtual function),使基类变成抽象(abstract)类。纯虚函数使用关键字virtual,并且在函数后面加上 =0. 相当于java的 abstract前缀

纯虚函数的语法
virtual void f() = 0;

  1. 抽象类无法实例化对象 和java一致。

  2. 抽象类的子类必须重写父类的纯虚函数 —》和java一致

构造函数不能为虚函数,但析构函数能够且常常必须使虚函数

虚析构和纯虚析构
问题:父类指针在析构时,不会调用子类的析构函数
利用虚析构可以解决这个问题。
纯虚析构 既要声明,也要实现。

实践

#include<stdio.h>
#include<iostream>
using namespace std;class BaseClass
{
public:BaseClass(){cout<< " BaseClass construct"<<endl;}//添加virtual关键字,告诉编译器,采用晚捆绑的方式,编译后会创建一个vfprt,指向vftable,存放print的地址virtual void print(){cout << " BaseClass print"<<endl;}~BaseClass(){cout<< " BaseClass destruct"<<endl;}
private:void innerMethod(){cout<< " BaseClass inner"<<endl;}
};class BaseClass2
{
public:BaseClass2(){cout<< " BaseClass2 construct"<<endl;}virtual void print(){cout << " BaseClass2 print"<<endl;}~BaseClass2(){cout<< " BaseClass2 destruct"<<endl;}
private:void innerMethod(){cout<< " BaseClass2 inner"<<endl;}
};class ChildClass : public BaseClass, private BaseClass2
{
public:ChildClass(){cout<< " ChildClass construct"<<endl;}void print(){BaseClass::print();// BaseClass::innerMethod(); //不能访问父类的私有函数或变量BaseClass2::print(); //私有继承,可以访问父类的public函数cout<< "ChildClass print"<<endl;}~ChildClass(){cout<< " ChildClass destruct"<<endl;}
};int main()
{BaseClass tmp;ChildClass childClass;//如果BaseClas中print设置virtual后,编译器分配一个指针vfptr,派生类也会继承该vfptrcout<<"size of BaseClass"<<sizeof(tmp)<<endl;cout<<"size of childClass"<<sizeof(childClass)<<endl;BaseClass *baseclass = &childClass; //创建BaseClass类 指向 childClassbaseclass->print();//如果print不加virtual,此时打印出的只有BaseClass的printreturn 0;
}

五、模版

继承和组合提供了重用对象代码的方法,而CPP的模版特征提供了重用源代码的方法,建立通用性的模版,大大提高复用性。

有点像工具类中的通用方法,但是有不仅限于此,通过泛型提供了更好的通用性,另外不仅有函数模版,还有类模版,下面我们一起来学习具体知识点:

特点:

  1. 模版只是一个框架,不能直接使用

  2. 模版不是万能的

模版的声明和定义通常放在头文件中,这看似违背了“头文件不要放置分配内存存储空间的任何东西”,但模版的定义比较特殊, 在template<…>之后的代码意味着编译器在当时不分配存储空间,等到被使用时才分配。

5.1 函数模版

使用场景:泛型编程

语法
template<typename T>
函数声明或者定义template --》声明创建模版
typename -->表示其后面的符号是一种数据类型,也可以用class替代
T --》通用的数据类型,名称可以替换,通常为大写字母

使用函数模版的方式
自动类型推导 —〉必须要推导
显示指定类型

函数注意事项
自动类型推导,必须推导出一致的数据类型T才可以使用。
模版必须要确定T的数据类型,才可以使用

普通函数与函数模版的区别
是否可以发生自动类型转换(隐式类型转换)

普遍函数可以,函数模版自动推导不可以,显示指定可以。
建议使用显示指定类型的方式调用函数模版

普通函数与函数模版的调用规则

  1. 如果函数模版和普通函数都可以实现,优先调用普通函数

  2. 可以通过空模版参数列表来强制调用函数模版

  3. 函数模版也可以发生重载

  4. 如果函数模版可以产生更好的匹配,优先调用函数模版
    即然提供了函数模版,最好就不要提供普通函数,否则容易出现二义性。

实践

#include<stdio.h>
#include<iostream>
#include<string>
using namespace std;template<typename T>
int add(T a,T b){cout <<"template T method"<<endl;return a + b;
}template<typename T, typename S>
int add(T a,S b){cout <<"template S T method"<<endl;return a + b;
}int add(int a,int b){cout <<"normal method"<<endl;return a + b;
}int main()
{cout <<"add "<< add(1,1)<< endl; //如果函数模版和普通函数都可以实现,优先调用普通函数cout <<"add "<< add<>(1,1)<< endl;//可以通过空模版参数,强制的调用模版函数cout <<"add "<< add(1.0,2.0)<< endl;cout <<"add "<< add(1.0,3)<< endl; //模版支持重载cout <<"add "<< add<int ,int>(1.0,3)<< endl; // cout <<"add "<< add("ab","ca")<< endl; // 错误,模版不是万能的,复合对类型才行return 0;
}

5.2 类模版

template<class T>
classtemplate --》声明创建模版
class -->表示其后面的符号是一种数据类型,当然也可以写为typename
T --》通用的数据类型,名称可以替换,通常为大写字母

类模版和函数模版的区别

  1. 类模版没有自动类型推导,只能使用显示指定类型

  2. 类模版在模版参数列表中可以有默认参数

类模版中成员函数的创建时机

  1. 普通类中的成员函数一开始就可以创建

  2. 类模版中的成员函数在调用时才可以创建

类模版对象做函数参数,三种方式

  1. 指定传入的类型 — 直接显示对象的数据类型

  2. 参数模版化 — 将对象中的参数变为模版进行传递

  3. 整个类模版化 — 将这个对象类型 模版化进行传递

实践

#include <iostream>using namespace std;template <class T>
class templateclass {
public://构造函数templateclass(T k = 10) { this->k = k;cout<< "templateclass construt k = "<<this->k <<endl;}void setValue(T k){this->k = k;}T getVaule() const { return k; }private:T k;
};// 使用类模板,函数参数必须显示指定类型
void print(templateclass<int>& params) {cout << params.getVaule() << endl;
}int main(void) {// templateclass<> p(100);//错误,类模版没有自动类型推导,只能使用显示指定类型templateclass<int> k(100);cout << k.getVaule() << endl;k.setValue(1000.5);//会被强制转为模版类声明的类型// k.setValue(“a”);//错误print(k);return 0;
}

收获

学习回顾了cpp的重要知识点,信息量还是比较大,重在回顾实践。

  1. 深拷贝与浅拷贝,

  2. this指针的定义和用处

  3. const修饰成员函数的作用

  4. 友元函数的意义

  5. 运算符重载方式以及意义

  6. 继承 虚基类 多继承、继承的三种方式的使用

  7. 多态 的定义已经使用场景 虚函数 纯虚函数 抽象类的理解

  8. 模版函数与模版类的使用

音视频开发系列(46)运算符重载、继承、多态、模版相关推荐

  1. 【音视频开发系列】一学就会,快速掌握音视频开发的第一个开源项目FFmpeg

    快速掌握音视频开发的第一个开源项目:FFmpeg 1.为什么要学FFmpeg 2.FFmpeg面向对象思想分析 3.FFmpeg各种组件剖析 视频讲解如下,点击观看: [音视频开发系列]一学就会,快速 ...

  2. 【音视频开发系列】盘点音视频直播RTSP/RTMP推流一定会遇到的各种坑,教你快速解决

    聊聊RTSP/RTMP推流那些坑 1.推流架构分析 2.推流缓存队列的设计 3.FFmpeg函数阻塞问题分析 [音视频开发系列]盘点音视频直播一定会遇到的各种坑,教你快速解决 更多精彩内容包括:C/C ...

  3. 【音视频开发系列】srs-webrtc-janus开源流媒体服务器分析

    全球最牛开源流媒体服务器源码分析 1.如何学习流媒体服务器 2.全球最牛流媒体服务器架构分析 3.我们能从全球最牛流媒体服务器得到什么 [音视频开发系列]srs-webrtc-janus流媒体服务器分 ...

  4. 音视频开发系列-H264编码原理

    H264简介 来自百度百科的介绍: H.264是国际标准化组织(ISO)和国际电信联盟(ITU)共同提出的继MPEG4之后的新一代数字视频压缩格式. H.264是ITU-T以H.26x系列为名称命名的 ...

  5. 音视频开发系列(16)技术解码 | SRT和RIST协议综述

    概要 近些年来,互联网行业出现了几波和音视频相关的热潮:VR.短视频.直播等.除了VR因技术成熟度问题,还在蓄势待发,短视频和直播持续热度不减,以各种方式进入新的行业应用领域.视频直播方向,RTMP仍 ...

  6. 音视频开发系列--H264编解码总结

    一.概述 H264,通常也被称之为H264/AVC(或者H.264/MPEG-4 AVC或MPEG-4/H.264 AVC) 对摄像头采集的每一帧视频需要进行编码,由于视频中存在空间和时间的冗余,需要 ...

  7. 音视频开发系列(19)玩转 WebRTC 安全通信:一文读懂 DTLS 协议

    在 WebRTC 中,为了保证媒体传输的安全性,引入了 DTLS 来对通信过程进行加密.DTLS 的作用.原理与 SSL/TLS 类似,都是为了使得原本不安全的通信过程变得安全.它们的区别点是 DTL ...

  8. 音视频开发系列(17)文章分享-提速 30%腾讯TQUIC 网络传输协议

    作者:腾讯 sTGW-TQUIC 腾讯sTGW如何助力核心业务用户登录耗时降低30%,下载场景500ms内请求成功率从HTTPS的60%提升到90%,移动端APP在弱网.跨网场景下同样取得媲美正常网络 ...

  9. 音视频开发系列(34) OpenGL ES 绘制平面图形

    我们前两篇介绍了OpenGL ES 基本概念和GLSL及Shader的渲染流程,这篇我们开始实战,通过GLSurfaceView加载着色器,来绘制三角形.正方形和直线这些平面图形.在实践过程中遇到的问 ...

最新文章

  1. 非聚集索引和聚集索引
  2. 实验吧——SQL注入 Write up(一)
  3. mac mysql php_Mac搭建php开发环境:Apache+php+MySql
  4. 回顾2009,展望2010
  5. Octave: 'rgb2gray' undefined error
  6. 相机模型和双目立体匹配
  7. 【超参数寻优】粒子群算法(PSO) 超参数寻优的python实现
  8. ip申请 web应用_阿里云同时部署DDoS高防IP+CDN+WAF
  9. c语言程序设计答案四,C语言程序设计练习四(参考答案)
  10. 如何反编译微信小程序前端,30分钟教你学会
  11. 数据拟合MATLAB与origin哪个好,Origin:数据处理、作图和拟合的利器
  12. 国内外接口文档工具哪家强?
  13. ie浏览器文档模式设置
  14. C++ 167. 两数之和 II 633. 平方数之和
  15. Nginx 的配置文件
  16. 两个路由器+两个主机:简单的网络配置
  17. 提示:The word is not correctly spelled 解决方法
  18. [二分][dp凸优化] Luogu P4383 林克卡特树lct
  19. 实时监控Mysql等数据库变化_进行数据同步_了解Maxwell_--MaxWell工作笔记001
  20. 人工智能浪潮中,AI如何为企业降本增效?

热门文章

  1. 用python实现分段函数_python:集成分段函数
  2. tt服务器系统,TT服务器使用手册.doc
  3. 2023年全国最新工会考试精选真题及答案46
  4. Bat_PNG转PDF,读取系统剪切板
  5. 详解怎么更新win10系统操作方法
  6. 海大11年春第5题:编程输出[m,n]之间所有素数,m,n由键盘输入。(10分)
  7. 网络对抗技术——实验四:恶意代码技术
  8. C语言实现通讯录1.0
  9. 动物识别 羊群识别 牛识别 马识别 yolo动物识别 鸟类识别 狗识别 猫狗分类
  10. win7查看隐藏文件夹