音视频开发系列(46)运算符重载、继承、多态、模版
一、类和对象的重要知识点
1.1 深拷贝与浅拷贝
浅拷贝:简单的赋值拷贝操作,拷贝构造
深拷贝:在堆区重新申请空间,进行拷贝操作
1.2 this指针
this指针指向被调用的成员函数所属的对象。
本质是指针常量(即指针的指向是不可以修改的,但指向的内容的值是可以修改的)
用途
当形参和成员变量同名时,可用this指针来区分
在类的非静态成员函数中返回对象本身,可使用
return * this 返回该对象的引用,达到链式编程
1.3 const修饰成员函数
常函数:
成员函数后加const,称这个函数为常函数,本质上是 修饰this指针指向,让指针指向的内容值也不可以修改. eg: 返回值 函数名() const
一般常函数内不可以修改成员属性
成员属性声明时加关键字mutable后,在常函数中依然可以修改
常对象:
声明对象前加const,称该对象为常对象 eg: const Object obj;
常对象只能调用常函数。
实践
#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表示
友元的三种实现
全局函数做友元
类做友元
成员函数做友元
实践
#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后就是运算符重载的语法糖效果。
运算符重载有两种方式:
成员函数
全局函数
运算符重载 也可以发生函数重载
对于内置的数据的类型的运算符无法改变,只可用于用户自定义类型。
不要滥用运算符重载
常用的运算符重载 “+”、“<<”、“++”、“=” “< > != ==”
下面以重载”+”运算符,实现两个对象相加。
#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)提供了接口与具体实现之间额一层隔离,改善了代码的组织结构和可读性,利于前后期的维护及扩展
动态多态满足条件
有继承关系
子类重写父类的虚函数
动态多态的场景:当父类的指针或者引用指向子类对象时,就发生了动态多态。
地址早绑定,在编译阶段确定了函数地址。
使用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;
抽象类无法实例化对象 和java一致。
抽象类的子类必须重写父类的纯虚函数 —》和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的模版特征提供了重用源代码的方法,建立通用性的模版,大大提高复用性。
有点像工具类中的通用方法,但是有不仅限于此,通过泛型提供了更好的通用性,另外不仅有函数模版,还有类模版,下面我们一起来学习具体知识点:
特点:
模版只是一个框架,不能直接使用
模版不是万能的
模版的声明和定义通常放在头文件中,这看似违背了“头文件不要放置分配内存存储空间的任何东西”,但模版的定义比较特殊, 在template<…>之后的代码意味着编译器在当时不分配存储空间,等到被使用时才分配。
5.1 函数模版
使用场景:泛型编程
语法
template<typename T>
函数声明或者定义template --》声明创建模版
typename -->表示其后面的符号是一种数据类型,也可以用class替代
T --》通用的数据类型,名称可以替换,通常为大写字母
使用函数模版的方式
自动类型推导 —〉必须要推导
显示指定类型
函数注意事项
自动类型推导,必须推导出一致的数据类型T才可以使用。
模版必须要确定T的数据类型,才可以使用
普通函数与函数模版的区别
是否可以发生自动类型转换(隐式类型转换)
普遍函数可以,函数模版自动推导不可以,显示指定可以。
建议使用显示指定类型的方式调用函数模版
普通函数与函数模版的调用规则
如果函数模版和普通函数都可以实现,优先调用普通函数
可以通过空模版参数列表来强制调用函数模版
函数模版也可以发生重载
如果函数模版可以产生更好的匹配,优先调用函数模版
即然提供了函数模版,最好就不要提供普通函数,否则容易出现二义性。
实践
#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 --》通用的数据类型,名称可以替换,通常为大写字母
类模版和函数模版的区别
类模版没有自动类型推导,只能使用显示指定类型
类模版在模版参数列表中可以有默认参数
类模版中成员函数的创建时机
普通类中的成员函数一开始就可以创建
类模版中的成员函数在调用时才可以创建
类模版对象做函数参数,三种方式
指定传入的类型 — 直接显示对象的数据类型
参数模版化 — 将对象中的参数变为模版进行传递
整个类模版化 — 将这个对象类型 模版化进行传递
实践
#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的重要知识点,信息量还是比较大,重在回顾实践。
深拷贝与浅拷贝,
this指针的定义和用处
const修饰成员函数的作用
友元函数的意义
运算符重载方式以及意义
继承 虚基类 多继承、继承的三种方式的使用
多态 的定义已经使用场景 虚函数 纯虚函数 抽象类的理解
模版函数与模版类的使用
音视频开发系列(46)运算符重载、继承、多态、模版相关推荐
- 【音视频开发系列】一学就会,快速掌握音视频开发的第一个开源项目FFmpeg
快速掌握音视频开发的第一个开源项目:FFmpeg 1.为什么要学FFmpeg 2.FFmpeg面向对象思想分析 3.FFmpeg各种组件剖析 视频讲解如下,点击观看: [音视频开发系列]一学就会,快速 ...
- 【音视频开发系列】盘点音视频直播RTSP/RTMP推流一定会遇到的各种坑,教你快速解决
聊聊RTSP/RTMP推流那些坑 1.推流架构分析 2.推流缓存队列的设计 3.FFmpeg函数阻塞问题分析 [音视频开发系列]盘点音视频直播一定会遇到的各种坑,教你快速解决 更多精彩内容包括:C/C ...
- 【音视频开发系列】srs-webrtc-janus开源流媒体服务器分析
全球最牛开源流媒体服务器源码分析 1.如何学习流媒体服务器 2.全球最牛流媒体服务器架构分析 3.我们能从全球最牛流媒体服务器得到什么 [音视频开发系列]srs-webrtc-janus流媒体服务器分 ...
- 音视频开发系列-H264编码原理
H264简介 来自百度百科的介绍: H.264是国际标准化组织(ISO)和国际电信联盟(ITU)共同提出的继MPEG4之后的新一代数字视频压缩格式. H.264是ITU-T以H.26x系列为名称命名的 ...
- 音视频开发系列(16)技术解码 | SRT和RIST协议综述
概要 近些年来,互联网行业出现了几波和音视频相关的热潮:VR.短视频.直播等.除了VR因技术成熟度问题,还在蓄势待发,短视频和直播持续热度不减,以各种方式进入新的行业应用领域.视频直播方向,RTMP仍 ...
- 音视频开发系列--H264编解码总结
一.概述 H264,通常也被称之为H264/AVC(或者H.264/MPEG-4 AVC或MPEG-4/H.264 AVC) 对摄像头采集的每一帧视频需要进行编码,由于视频中存在空间和时间的冗余,需要 ...
- 音视频开发系列(19)玩转 WebRTC 安全通信:一文读懂 DTLS 协议
在 WebRTC 中,为了保证媒体传输的安全性,引入了 DTLS 来对通信过程进行加密.DTLS 的作用.原理与 SSL/TLS 类似,都是为了使得原本不安全的通信过程变得安全.它们的区别点是 DTL ...
- 音视频开发系列(17)文章分享-提速 30%腾讯TQUIC 网络传输协议
作者:腾讯 sTGW-TQUIC 腾讯sTGW如何助力核心业务用户登录耗时降低30%,下载场景500ms内请求成功率从HTTPS的60%提升到90%,移动端APP在弱网.跨网场景下同样取得媲美正常网络 ...
- 音视频开发系列(34) OpenGL ES 绘制平面图形
我们前两篇介绍了OpenGL ES 基本概念和GLSL及Shader的渲染流程,这篇我们开始实战,通过GLSurfaceView加载着色器,来绘制三角形.正方形和直线这些平面图形.在实践过程中遇到的问 ...
最新文章
- 非聚集索引和聚集索引
- 实验吧——SQL注入 Write up(一)
- mac mysql php_Mac搭建php开发环境:Apache+php+MySql
- 回顾2009,展望2010
- Octave: 'rgb2gray' undefined error
- 相机模型和双目立体匹配
- 【超参数寻优】粒子群算法(PSO) 超参数寻优的python实现
- ip申请 web应用_阿里云同时部署DDoS高防IP+CDN+WAF
- c语言程序设计答案四,C语言程序设计练习四(参考答案)
- 如何反编译微信小程序前端,30分钟教你学会
- 数据拟合MATLAB与origin哪个好,Origin:数据处理、作图和拟合的利器
- 国内外接口文档工具哪家强?
- ie浏览器文档模式设置
- C++ 167. 两数之和 II 633. 平方数之和
- Nginx 的配置文件
- 两个路由器+两个主机:简单的网络配置
- 提示:The word is not correctly spelled 解决方法
- [二分][dp凸优化] Luogu P4383 林克卡特树lct
- 实时监控Mysql等数据库变化_进行数据同步_了解Maxwell_--MaxWell工作笔记001
- 人工智能浪潮中,AI如何为企业降本增效?