目录

  1. 类和对象的重要知识点

  2. 运算符重载

  3. 继承

  4. 多态

  5. 模版

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

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. 常对象只能调用常函数。

本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,编解码,推拉流,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

实践

#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;
}

三、继承

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

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。

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

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

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

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

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

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

本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,编解码,推拉流,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

实践

#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;
}

本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,编解码,推拉流,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

音视频开发(十九):运算符重载、继承、多态、模版相关推荐

  1. 音视频开发系列(46)运算符重载、继承、多态、模版

    一.类和对象的重要知识点 1.1 深拷贝与浅拷贝 浅拷贝:简单的赋值拷贝操作,拷贝构造 深拷贝:在堆区重新申请空间,进行拷贝操作 1.2 this指针 this指针指向被调用的成员函数所属的对象. 本 ...

  2. 即时通讯音视频开发(十八):详解音频编解码的原理、演进和应用选型

    1.引言 大家好,我是刘华平,从毕业到现在我一直在从事音视频领域相关工作,也有一些自己的创业项目,曾为早期Google Android SDK多媒体架构的构建作出贡献. 就音频而言,无论是算法多样性, ...

  3. 即时通讯音视频开发(十):实时语音通讯的回音消除技术详解

    前言 即时通讯应用中的实时音视频技术,几乎是IM开发中的最后一道高墙.原因在于:实时音视频技术 = 音视频处理技术 + 网络传输技术 的横向技术应用集合体,而公共互联网不是为了实时通信设计的.有关实时 ...

  4. 即时通讯音视频开发(十四):实时音视频数据传输协议介绍

    概述 随着移动互联网的快速发展以及智能终端性能的逐步提高,智能终端间进行实时音视频通讯成为移动互联网发展的一个重要方向.那么如何保证智能终端之间实时音视频数据通讯成为一个很现实的问题. 实际上,实时音 ...

  5. 技术福利:最全实时音视频开发要用到的开源工程汇总

    [转自] https://my.oschina.net/jb2011/blog/1619628 1.前言 实时音视频的开发学习有很多可以参考的开源项目.一个实时音视频应用共包括几个环节:采集.编码.前 ...

  6. 实时音视频开发理论必备:如何省流量?视频高度压缩背后的预测技术

    本文引用了"拍乐云Pano"的"深入浅出理解视频编解码技术"和"揭秘视频千倍压缩背后的技术原理之本文引用了"拍乐云Pano"的&q ...

  7. 即时通讯音视频开发(0):零基础,史上最通俗视频编码技术入门

    [来源申明]本文引用了微信公众号"鲜枣课堂"的<视频编码零基础入门>文章内容.为了更好的内容呈现,即时通讯网在引用和收录时内容有改动,转载时请注明原文来源信息,尊重原作 ...

  8. 音视频开发入门(4):视频编解码之预测技术介绍

    上一节的图中有一个表示显示的图像序列与编码序列是不同的,不知道大家注意到没有,这个图很重要,编码是有固定规则的,视屏播放时,并不是按照各帧达到顺序播放的,而是按照这个规则进行播放. 前言 即时通讯应用 ...

  9. 音视频开发入门(3):视频编解码之编码基础

    前言 即时通讯应用中的实时音视频技术,几乎是IM开发中的最后一道高墙.原因在于:实时音视频技术 = 音视频处理技术 + 网络传输技术 的横向技术应用集合体,而公共互联网不是为了实时通信设计的.有关实时 ...

最新文章

  1. EhCache 分布式缓存/缓存集群
  2. matlab 万能,matlab 万能实用的线性曲线拟合方法
  3. [css] 你了解CSS Houdini吗?说说它的运用场景有哪些?
  4. 二叉树小球下落问题c语言,#C++初学记录(树和二叉树)
  5. 伸缩杆怎么缩回去图解_没有阳台怎么晾衣服?这10个神器,让家里衣物晾晒更轻松方便...
  6. java基本数据类型以及相关内容总结
  7. html获取节点属性,JS操作属性节点(非常详细)
  8. DEDE织梦标签名称:{/dede:arclist} 详解
  9. [C#] C#访问数据库的代码(Access版本)
  10. 【Spring揭秘】Spring简介
  11. HttpSession基础
  12. 数据库实验3 表、ER图、索引和视图的基础操作
  13. 计算机导论.mobi,计算思维:计算学科导论
  14. 树莓派屏幕显示No Signal
  15. php开发接口,生成动态签名校验
  16. 第二讲:双活灾备方案建设方法论
  17. 决策树分类算法的案例(代码实现及运行测试)
  18. Android和DLT日志系统
  19. GPRC 和RPC 有什么区别?GPRC和RPC的区别是什么?
  20. 亿赛通携手湖北省勘察设计协会 共建数据安全

热门文章

  1. Java基础之MySQL数据库与JDBC
  2. OpenCV参考手册之Mat类详解(一)
  3. TRL街道审核软件包简介
  4. java邮件发送代码报错_javamail发送附件不通过也不报错
  5. 英超前瞻乐.fun|体育 中秋利物浦主场对战狼队 历史交战能否延续全胜
  6. 牵手华为云,云时通SRM助力企业采购数字化升级!
  7. 会做饭的机器人曰记_会做饭的机器人!
  8. C++ 读取txt文件中数据并存入数组中
  9. java 获取meta-inf路径_【Java】WEB-INF目录与META-INF目录的作用
  10. 关于在控制面板上软件卸载失败的问题