【C++】侯捷C++面向对象高级编程(下)

news2024/12/28 20:28:06

转换函数(conversion function)

  • 可以把"这种"东西,转化为"别种"东西。

  • 即Fraction ——> double

class Fraction {
public:
	Fraction(int num, int den = 1) :
		m_numerator(num), m_denominator(den) {
	}
	operator double()const {
		return ((double)m_numerator / m_denominator);
	}
private:
	int m_numerator;  //分子
	int m_denominator;//分母
};
Fraction f(3,5);
double d = 4 + f;

说明:

  • 编译器先去查找是否有支持的函数能让这行代码通过。
  • 是否有operator+(double,Fraction),重载了+号。
  • 没有,则看能否将f转换为double。找到了operator double()const。
  • 于是f变成了0.6。
std::cout << typeid(f).name()<<std::endl;//class Fraction
std::cout << d <<std::endl;//4.6

注意:

  • 我在侯捷老师的视频中的发现了一个小问题。
  • image-20220720231907092
  • 如上图所示(double)的位置写的不对,应任意写到后两个变量的前面,如我上面类的代码所示。

non-explicit-one-argument-ctor

  • 具有一个实参的构造函数()

  • 可以把"别种"东西,转化为"这种"东西。

  • 即double ——> Fraction

class Fraction
{
public:
	Fraction(int num,int den = 1):
    	m_numerator(num),m_denominator(den){}
    
    Fraction operator+(const Fraction& f){
        return Fraction(...);
    }
private:
	int m_numerator;  
	int m_denominator;
};
Fraction f(3,5);
double d = 4 + f;

说明:

  • 可以看到在Fraction类中我们重载了+运算符,可以使两个Fraction对象进行相加。
  • 但是我们下面进行调用的时候使用的是一个整数与一个Fraction对象进行相加。
  • 此时调用的形式与我们的设计不同,于是编译器去看看能不能将4转换为Fraction,如果可以转换,则符合了我们的+重载。
  • 于是调用我们的构造函数Fraction(int num,int den = 1),将4转换为Fraction,进行加法。

转换冲突

  • 此时,我们将上面两个例子中的两个成员函数整合。
class Fraction
{
public:
	Fraction(int num,int den = 1):
    	m_numerator(num),m_denominator(den){}
    
    operator double()const {
		return ((double)m_numerator / m_denominator);
	}
    
    Fraction operator+(const Fraction& f){
        return Fraction(...);
    }
private:
	int m_numerator;  
	int m_denominator;
};
Fraction f(3,5);
double d = 4 + f;
  • 编译器报错,不知道该如何是好。
  • 是4——>Fraction,还是Fraction——>4。
  • 产生歧义。

explicit-one-argument ctor

  • 给构造函数添加explict关键字,此时"别种"东西无法转换为"这种"东西即Fraction对象。
  • 不让编译器去暗度陈仓地偷偷调用构造函数。
  • 只有真正需要构造的时候采取调用。
class Fraction
{
public:
	explicit Fraction(int num,int den = 1):
    	m_numerator(num),m_denominator(den){}
    
    operator double()const {
		return ((double)m_numerator / m_denominator);
	}
    
    Fraction operator+(const Fraction& f){
        return Fraction(...);
    }
private:
	int m_numerator;  
	int m_denominator;
};
Fraction f(3,5);
double d = 4 + f;

说明:

  • 此时4向Fraction转换失败。f被转成double进行计算,结果为4.6

  • explicit多数用在构造函数处,少数还有在模板处。


标准库应用

image-20220721220738385


类指针类(pointer-like classes)

智能指针

  • 这个class创建的对象像指针。
  • 因为想要它比普通指针多做一些事情。
  • 即智能指针。

image-20220722175624295

注意:"->"这个符号很特别

  • 例如说,上图右侧中的* sp中的,* 号,在使用后就会消失。
  • 但是sp->method(),我们可以看到,调用sp->在右侧的类中,返回px,再往下看px->method(),会发现,这里其实少了一个->,这里就体现出这个符号的特殊性了,得到的东西会继续用箭头符号作用上去。

迭代器

  • 在运算符上比智能指针需要重载更多运算符,处理更多功能。
  • 有特别功能的智能指针。
  • 主要用于遍历容器。

image-20220722181438891

  • 示例——标准库中的list迭代器
  • foo即data
  • 注意与上面智能指针重载运算符的对比。

image-20220722182803315

说明:

  • 左边方框中的内容等同于右边话蓝线的部分。

仿函数(function-like classes)

  • 设计一个类,让它的行为像函数。
  • 小括号操作符,就叫做函数调用操作符。
  • 所以如果有一个东西可以接受小括号操作符,就把这个东西称作函数,或者是一个像函数的东西。

image-20220731175954580

  • 具体的相关继承问题详见STL库部分。

namespace经验之谈

  • 分块开发,避免命名冲突。

模板(template)

类模板(class template)

  • 定义类的时候将允许使用者任意指定的类型抽出来。
  • 使用时需要进行类型的指定。

image-20220731184131481


函数模板(function template)

  • 使用不需要指定类型。
  • 编译器会自动进行实参推导。

image-20220731195049956

说明:

  • 首先编译模板。
  • 接着再次编译,判断stone类型的运算是否合法。

成员模板(member template)

  • 也就是模板的嵌套,模板中有模板。
  • 如下图黄色部分。

image-20220731195410159

说明: 黄色这一块是当前模板的一个成员,同时它自己也是个模板。所以它就叫做成员模板。

  • T1,T2可以变化,U1,U2也可以变化。

在STL标准库中会大量出现成员模板,先来一个小示例:

解释:

  • 鲫鱼类继承自鱼类,麻雀类继承自鸟类。
  • 使用鲫鱼和麻雀构成的pair,然后拷贝到到鱼类和鸟类构成的pair,这样是可以的。反之则不行。
  • 允许或不允许限制的条件为: 下方代码中的构造函数。(父类指针可以指向子类对象)
  • 这样,让构造函数更有弹性
template<calss T1,class T2>
struct pair{
    ...

    template<class U1,class U2>
    pair(const pair<U1,U2>&p):first(p.first),second(p.second){}
};
  • shard_ptr内的使用

image-20220925210959276

  • 同普通指针的,父类指针可以指向子类对象。
  • 补充:C++ Upcast(向上造型)
  • up-cast为向上构造
  • down-cast为向下构造

模板特化(specialization)

全特化

  • 泛化的反面就是特化
  • 泛化(又叫全泛化)指的是用的时候指定类型
  • 根据特定的类型进行特殊处理,类似于函数重载。

image-20220925212047290

// 泛化
#include <iostream>
using namespace  std;

// 泛化
template<class  Key>
struct hash1{};


// 特化
template<>
struct hash1<char>{
    size_t operator()(char x)const {
        return x;
    }
};

template<>
struct hash1<long>{
    size_t operator()(long x)const {
        return x;
    }
};

int main(void){
    // 调用
    hash1<long>()(1000);// 构造一个hash的临时对象,传递参数1000,找到上面的特化long

    return 0;
}
  • 与全特化对应的是偏特化(局部特化)

偏特化

  • 个数上的偏
  • 从左边开始绑定,不能跳。

  • 范围上的偏
  • 例如,从接收任意范围T,到接收指针T*


模块模板参数(tempalte template parameter)

  • 即,模板的参数又是一个模板

image-20221223192522559

  • 如上图所示,传递任意的容器与元素类型进行组合
    • 其中第一个打岔的部分,光看语法上并没有问题,但是,实际上在我们定义容器的时候有多个默认参数,这样做是无法通过编译的。
    • 但是第二个OK

这个不是模板模板参数

image-20221223205927384

  • 调用中我们使用第二种方法,指明第二模板参数,其实这个list< int >就已经不是模板了,已经指明了,即使它是用模板设计出来的东西。
  • 但是已经绑定,写死,list中的元素类型为int;
  • 注意与本小节第一张图对比。
  • 所以temp<class T,class Sequence = deque< T >>第二个参数,不是模板模板参数。

可变参数模板(variadic templates-since)

  • 模板可接收任意个参数,详见下方示例:
#include <iostream> 
#include <bitset>
using namespace std;

void print(){}

// 分为一个和一包 
template<typename T,typename... Types>
void print(const T& firstArg,const Types&...args) {
   cout<<firstArg<<endl;
   print(args...);// 调用,将这一包拆开 
   // 注意: 到最后变成0个的时候,将会调用上面的print() 
   cout<<sizeof...(args)<<endl;// 获得这一包中有几个元素 
}
int main(void){
   print(7.5,"hello",bitset<16>(377),42);
   return 0;
}

自动类型推导(auto)

  • 示例
list<string>c;
//...
list<string>::iterator ite;
ite = find(c.begin(),c.end(),target);
  • 使用实例
auto ite = find(c.begin(),c.end(),target);//  定义使用时就赋值
  • 错误使用
auto ite;// 编译器不能也无法知道这个ite是什么,无法进行推导
ite = find(c.begin(),c.end(),target);

更简洁的for(ranged-base for)

for(decl: coll){
	statement
}
  • 示例
vector<double>vec;
//...

// pass by value 传值
for(auto elem:vec){
    cout<<elem<<endl;
}
// pass by reference 传引用——改变原来的东西
for(auto& elem:vec){
    elem *=3;
}

引用(reference)

  • 引用一定要设初值,且之后无法再代表其它值。
  • 示例
	int x = 0;
	int* p = &x;// p指向x 
	int& r = x;// r代表x 
	
	int x2 = 5;
	
	r = x2;// x r都为5,相当于将值5赋给x 
	
	int& r2 = r; 
  • 有趣的一点: 编译器制造出的假象
    • 大小相同,地址也相同
sizeof(r) == sizeof(x);
&x == &r; 

  • referece 就是一种漂亮的pointer
    • 多用于参数传递——传引用

image-20221223233254829


  • same signature——相同函数签名,二者无法并存
    • 函数名和参数列表包括后面的const为signature(函数签名)
      • const 是函数签名(signature)的一部分
    • 编译器不知道你调用的是谁
double imag(const double& im){...}
double imag(const double im){...}

对象模型(Object Model)

继承下的构造与析构

  • 构造——由内而外
    • 子类构造时,会先执行父类的默认构造函数,编译器会默认加上并执行。
  • 析构——由外而内
    • 子类析构时,会先析构掉自己执行完后,然后指定父类的默认析构函数,同样由编译器添加并执行。

复合下的构造与析构

  • 构造——由内而外

  • 析构——由外而内


继承+复合下的构造与析构

  • 构造——由内而外
    • 但是此时内有两个,也许在不同编译器上的实现手法不同,可能会导致顺序不同。
  • 析构——由外而内
    • 同上,要注意的是,上面先构造的,会后析构。

虚指针与虚函数表(vptr & vtbl)

  • 虚指针指向虚函数表,虚函数表中都是函数指针。
  • 虚函数的调用&执行,如下图所示:

image-20221224141619682

  • 调用虚函数的过程为动态绑定——即多态,父类指针可以接收具体的子类对象,即根据具体是哪个子类,调用该虚函数具体的形式。
    • 调用指针->向上转型(转为具体的子类)->调用虚函数
  • 补充:
    • 继承父类,函数,继承的是调用权。
    • 父类的虚函数子类也一定要有。
    • 父类和子类中可以出现同名的函数,但实际上不是同一个。

this pointer

  • 类的成员函数中,默认会有一个this指针传递进来。由编译器自己处理。

image-20221224221135995


补充

const

  • 修饰成员函数——即放到成员函数参数列表后:
    • 表明该成员函数不打算修改成员变量的值
    • 让编译器帮忙把关,如果修改了,则无法通过编译。
  • 常量对象不能调用非常量成员函数,反之,可以。
    • 但是,当成员函数的const版本和非const版本都存在,则常量对象只能调用const版本,非const对象只能调用非const版本。
  • 能加const就加const
  • const属于函数签名的一部分
  • 示例: 标准库中的string,区分调用者的意图:

image-20221224232341559


new & delete

  • 三种new——参考: C++ new的三种面貌
    • new (operator): 即关键字new,实际在堆中分配内存时,调用下面两个
    • operator new: 用于申请堆内存空间,类似于C语言中的malloc()
    • pleacement new: 即放置new,在人为指定的特定内存创建对象,是一个特殊的operator new,对其进行了重载。
  • 调用new实际上被分解为三条语句——表达式行为不能被修改,也就是分解的这件事情不能被修改,但是分解下去调用的函数可以被重载
//调用
MyComplex *pc = new MyComplex(1,2);


void* temp = operator new(sizeof(MyComplex));// 分配内存-相当于调用malloc(n)
pc = static_cast<MyComplex*>(temp);//转型
pc->MyComplex::MyComplex(1,2);//调用构造函数

  • delete实际上被分解为两条语句
delete pc;

Complex::~Complex(pc);
operator delete(pc);//(即 调用free)

重载::operatpr new,::operator delete,::operator new[],::operator delete[]

image-20221225100615799


重载member operator new/delete

  • 一个对象

image-20221225102320444


重载member operator new[]/delete[]

  • 数组

image-20221225101300115


示例

  • 若无成员函数就调用globals
  • 也可以强制使用globals

image-20221225101419034

  • 这个多出来的4是一个计数器,数组中的元素个数(gnu c)
    • 无论你是否重载,这个计数器都会存在。

image-20221225102055964


重载pleacement new,pleacement delete

  • 类的成员函数,可以重载多个版本,每一个版本都要有独一无二的参数列。
    • 第一个参数必需为size_t——大小
    • 其余参数为使用时()中指定的参数,例如下方示例中的300,‘c’
  • 重载operator delete()后,绝对不会被delete调用,只有当new所调用的构造函数抛出异常,才会调用这些版本的operator delete()
    • 不是必须的,可重载,可不重载
  • 示例
Foo* pf = new(300,'c')Foo;

image-20221225190302180


basic_string使用new

  • 当我们想在分配内存的时候无声无息的多分配一些,可以借用下面的思想。

image-20221225182352033

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

hashmap哈希map是什么?什么时候需要使用hashmap?C实现hashmap示例

背景 对于C程序员&#xff0c;尤其是嵌入式C程序员&#xff0c;hashmap使用的相对较少&#xff0c;所以会略显陌生&#xff0c;hashmap其实涉及到2个概念&#xff0c;分别是哈希(hash)、map。 哈希hash&#xff1a;是把任意长度输入通过蓝列算法变换成固定长度的输出&#xff…

CSS Flex 布局的 flex-direction 属性讲解

flex-direction 设置了主轴&#xff0c;从而定义了弹性项目放置在弹性容器中的方向。 Flexbox 是一种单向布局概念&#xff0c;可将弹性项目视为主要以水平行或垂直列布局。 .container {flex-direction: row | row-reverse | column | column-reverse; }几种支持的属性&#x…

devServer和VueCli | Webpack

文章目录devServer和VueCliwebpack-dev-servercontentBase模块热替换开启HMRhotOnly host配置port open compressproxyresolveextensions和alias配置如何区分开发环境devServer和VueCli webpack-dev-server contentBase 模块热替换 开启HMR hotOnly host配置 port open compres…

IMX6ULL学习笔记(15)——GPIO接口使用【官方SDK方式】

一、GPIO简介 i.MX6ULL 芯片的 GPIO 被分成 5 组,并且每组 GPIO 的数量不尽相同&#xff0c;例如 GPIO1 拥有 32 个引脚&#xff0c; GPIO2 拥有 22 个引脚&#xff0c; 其他 GPIO 分组的数量以及每个 GPIO 的功能请参考 《i.MX 6UltraLite Applications Processor Reference M…

有没有股票实时行情的同花顺l2接口?

对于个人投资者而言&#xff0c;一般看盘平台软件系统中&#xff0c;通过自定义公式接口&#xff0c;可以获取到股票实时行情的。例如同花顺l2接口系统会通过一些输入的公式就能查找指定的股票行情了&#xff0c;那么这个就相当于股票实时行情的API接口一样的道理&#xff0c;输…

加密解决HTTP协议带来的安全问题

HTTP协议默认是采取明文传输的&#xff0c;容易被中间人窃听、拦截、篡改&#xff0c;存在安全隐患。 常见提高安全性的方法是对通信内容进行加密&#xff0c;再进行传输&#xff0c;常见的加密方式有 不可逆加密&#xff1a;单向散列函数 可逆加密&#xff1a;对称加密、非对称…

从模型到服务——iDesktopX处理自动化工具实现BIM模型到三维服务发布

目录前言一、 处理自动化模型二、 算子参数设置1、 使用迭代数据集打开导出后的BIM模型2、 移除重复点、重复面和重复子对象3、 模型生成缓存4、 三维切片缓存发布5、 执行结果前言 BIM模型在SuperMap实际使用的业务流程中常常需要在桌面产品中生成缓存&#xff0c;然后通过iS…

安装和配置MySQL

首先前往官网下载mysql社区版&#xff08;不要钱&#xff09; MySQL Community Serverhttps://dev.mysql.com/downloads/windows/installer/8.0.html 甲骨文比较鸡贼&#xff0c;会要求你注册一个账号。但是下面有一行小字&#xff0c;直接点击下载就好了 双击后直接按…

Blender——苹果的纹理绘制

效果图 前言 在进行纹理绘制之前&#xff0c;首先要具有苹果三维模型。 关于苹果的建模请参考&#xff1a;Blender——“苹果”建模_行秋的博客 1.苹果UV的展开 1.1首先点击UV Eidting&#xff0c;滑动三维模型&#xff0c;使其大小适中。 1.2打开左上角的UV选区同步&#x…

使用idb操作IndexedDB

使用idb操作IndexedDB 译自&#xff1a;https://www.hackernoon.tech/use-indexeddb-with-idb-a-1kb-library-that-makes-it-easy-8p1f3yqq GitHub地址&#xff1a;https://github.com/jakearchibald/idb 文章目录使用idb操作IndexedDB前置条件本文承诺上手demo1&#xff1a;…

python中的encode()和decode()函数

前言&#xff1a; 我们知道&#xff0c;计算机是以二进制为单位的&#xff0c;也就是说计算机只识别0和1,也就是我们平时在电脑上看到的文字&#xff0c;只有先变成0和1&#xff0c;计算机才会识别它的意思。这种数据和二进制的转换规则就是编码。计算机的发展中&#xff0c;有…

【SpringCloud Alibaba】Sentinel流控规则

概念 流控规则 直接&#xff08;默认&#xff09; QPS快速失败 线程数直接控制 QPSWarming up QPS排队等待 关联 链路 具体启动Sentinel的步骤可以参考我的上一篇文章。 概念 资源名&#xff1a;唯一名称&#xff0c;默认请求路径 针对来源&#xff1a;Sentinel可以针…

微服务系列之远程服务调用

随笔 对自己不满是任何有才能的人的根本特征 参考书籍&#xff1a; “凤凰架构”“微服务架构设计模式” 本篇文章开始之前提示一下&#xff0c;读者带着“IPC与RPC的有什么区别”疑惑读效果更好 引言 从架构师的角度来看&#xff0c;微服务架构的落地实现第一个需要解决问…

改良型新药之详细分类

随着一类新药开发越来越困难、仿制药竞争激烈&#xff0c;改良型新药被认为符合我国医药企业转型升级的方向&#xff0c;吸引了更多企业切入&#xff0c;本文也将针对改良型新药的6个常见共性问题给予解答&#xff0c;涉及科普、专利、分类、临床价值、立项、注册申请、数据统计…

windows@网络防火墙@软件联网控制

文章目录ref打开防火墙控制面板常用部分限制某个软件联网文档参考具体操作取消控制/禁用第三方软件控制ref (Windows) 创建出站端口规则 | Microsoft LearnWindows Defender Firewall with Advanced Security (Windows) | Microsoft Learn组策略 Windows) 高级安全性的 Window…

你可能不知道的DOM断点调试技巧

前言 作为一个前端&#xff0c;DOM断点应该是我们非常熟悉的&#xff0c;也是我们日常工作中经常要用到的一种调试技巧&#xff1b;但是下面这些DOM断点调试技巧你可能不知道&#xff0c;且听我一一道来。 监听元素 有这样一种场景&#xff0c;当DOM中某个元素移除或者元素属…

再学C语言14:基本运算符

C使用运算符&#xff08;operator&#xff09;代表算数运算 一、赋值运算符&#xff08;assignment operator&#xff09;&#xff1a; 在C中&#xff0c;符号并不表示“相等”&#xff0c;而是一个赋值运算符 year 2022; 符号左边是一个变量名&#xff0c;右边是赋给该变…

arraybuffer的应用,下载图片/文件等

在这篇文章中&#xff0c;我们了解了js中arraybuffer是用来存储二进制缓存的&#xff0c;但是都是理论知识&#xff0c;本篇文章来介绍一个arraybuffer应用的场景。 主要应用场景是下载文件&#xff0c;在ajax请求中&#xff0c;设置responseType arraybuffer 得到一个二进制…

零刻 SEi12 Pro,ALL IN ONE搭建教程

一台mini的NUC能做什么&#xff1f;当然每个人的心里都会有着不同的答案&#xff0c;既然是一台Mini主机那就肯定少不了部署一个All-In-One来榨干他的性能。今天我就大家带来一个部署All-In-One的详细教程&#xff0c;希望能够对大家有帮助。 我这台机器配置是i5-1240P 16G内存…

【mpvue】mpvue-echarts echarts动态渲染、延迟加载、双轴动态计算、双轴对齐

mpvue-echarts 双轴折线案例使用echarts双轴折线图实战项目导入一、打包结果超过小程序大小限制&#xff1f;1.下载自定义echarts.js2. 引入 echarts.js![在这里插入图片描述](https://img-blog.csdnimg.cn/ff4ad6d894404e97bceff0581fc1f736.png#pic_center)3. 项目引入二、图…