C++程序设计兼谈对象模型(侯捷)笔记

C++程序设计兼谈对象模型(侯捷)

这是C++面向对象程序设计的续集笔记,仅供个人学习使用。如有侵权,请联系删除。

主要内容:涉及到模板中的类模板、函数模板、成员模板以及模板模板参数,后面包含对象模型中虚函数调用(动态绑定)的具体原理。

参考链接:

Youtube: C++面向对象高级开发(下)

Github:源码和PPT

文章目录

  • C++程序设计兼谈对象模型(侯捷)
    • 2 conversion function 转换函数
    • 3 non-explicit-one-argument constructor
    • 4 pointer-like classes
    • 5 function-like classes
    • 6 namespace经验谈
    • 7 class template 类模板
    • 8 function template 函数模板
    • 9 member template 成员模板
    • 10 specialization 模板特化
    • 11 模板偏特化
    • 12 模板模板参数
    • 13 关于C++标准库
    • 14 三个主题 variadic templates等
    • 15 reference
    • 16 复合&继承关系下的构造和析构
    • 17 (对象模型)关于vptr和vtbl,虚指针和虚表
    • 18 (对象模型)关于this
    • 19 (对象模型)关于Dynamic Binding
    • 后记

2 conversion function 转换函数

conversion function 转换函数

把这种东西转变为别的类型:把Fraction转变为double

class Fraction
{
public:Fraction(int num, int den=1): m_numerator(num), m_denominator(den) {}operator double() const{ // 转换函数,没有return type返回类型, 没有参数return (double) (m_numerator / m_denominator);}private:int m_numerator; // 分子int m_denominator; // 分母
}// 使用
Fraction f(3, 5);
double d = 4 + f;  // 调用operator double() 将f转换为0.6

3 non-explicit-one-argument constructor

one argument: 只要1个实参就够了, 注意和parameter的区别,下面的Fraction构造函数有两个parameter,但是只有一个argument。

non explicit one argument constructor的作用:可以把别的东西转变为这种类型

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 d2 = f + 4;  // 调用non-explicit constructor 将4转为 Fraction(4, 1), 然后调用operator+

如果 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);}Fraction operator+(const Fraction& f) {return Fraction(......); }private:int m_numerator; // 分子int m_denominator; // 分母
}// 使用
Fraction f(3, 5);
Fraction d2 = f + 4;  // 【Error】ambiguous

explicit-one-argument constructor

explicit关键字的作用是防止类构造函数的隐式自动转换.

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);
Fraction d2 = f + 4;  // 【Error】conversion from "double" to "Fraction" requested.

转换函数在标准库中的例子

template<class Alloc>
class vector<bool, Alloc>
{
public:typedef __bit_reference reference;
protected:reference operator[](size_type n) {return *(begin() + difference_type(n));}...
}struct __bit_reference {unsigned int* p;unsigned int mask;...
public:operator bool() const {return !(!(*p & mask));}
...
}

如下图所示:一个vector里面保存的都是bool值,然后返回的是reference类型,这里就要有bool的转换函数。另外下图中还涉及到一种设计模式:proxy,具体关于proxy的知识不展开。

在这里插入图片描述

4 pointer-like classes

pointer like classes 关于智能指针

为什么要把一个类设计出来像一个指针呢?比指针做的事情更多一点

template<class T>
class shared_ptr
{
public:T& operator*() const //*号操作符重载{ return *px;} // 传指针指向的内容T* operator->() const // -> 操作符重载{ return px;}shared_ptr(T* p): px(p) {}
private:T* px;long* pn;
};struct Foo
{...void method(void) {......}
}// 使用
shared_ptr<Foo> sp(new Foo); // 传一个指针进来Foo f(*sp); // 使用*这个操作符
sp->method(); // 使用->这个操作符

在这里插入图片描述

pointer like classes,关于迭代器

迭代器也像指针,指向一个元素


template<class T>
struct __list_node {void* prev;void* next;T data;
};template<class T, class Ref, class Ptr>
struct __list_iterator {typedef __list_iterator<T, Ref, Ptr> self;typedef Ptr pointer;typedef Ref reference;typedef __list_node<T>* link_type;link_type node;bool operator==(const self& x) const {return node == x.node;}bool operator!=(const self& x) const {return node != x.node;}reference operator*() const {return (*node).data;}pointer operator->() const {return &(operator*());}self& operator++() { node = (link_type)((*node).next); return *this;}self operator++(int) { self tmp = *this; ++*this; return tmp;}self& operator--() { node = (link_type)((*node).prev); return *this;}self operator--(int) { self tmp = *this; --*this; return tmp;}
}
T&
operator*() const {return (*node).data;} // 对迭代器解参考,就是拿链表节点中的dataT* 
operator->() const {return &(operator*());} // 获得上面operator*操作的地址

在这里插入图片描述

5 function-like classes

function like classes,所谓仿函数

重载()符号的用意,就是让这个类创建出来的对象是函数对象。

template<class T1, class T2>
struct pair {T1 first;T2 second;pair(): first(T1()), second(T2()) {}pair(const T1& a, const T2& b): first(a), second(b) {}
};template<class T>
struct identity {const T&operator()(const T& x) const {return x;}
};template <class Pair>
struct select1st {const typename Pair::first_type&operator()(const Pair& x) const{ return x.first;}
};template <class Pair>
struct select2nd {const typename Pair::second_type&operator()(const Pair& x) const{ return x.second;}
};

在这里插入图片描述

标准库中的仿函数的奇特模样:继承自unary_function

template<class T>
struct identity: public unary_function<T, T> {const T&operator()(const T& x) const {return x;}
};template <class Pair>
struct select1st: public unary_function<Pair, typename Pair::first_type> {const typename Pair::first_type&operator()(const Pair& x) const{ return x.first;}
};template <class Pair>
struct select2nd: public unary_function<Pair, typename Pair::second_type>  {const typename Pair::second_type&operator()(const Pair& x) const{ return x.second;}
};

还有继承自binary_function的仿函数

标准库中,仿函数所使用的奇特的base classes

在这里插入图片描述

6 namespace经验谈

命名空间起到隔离的作用,不同的命名空间里面可以有相同的函数名、变量名等,但是它们属于不同的范围。

在这里插入图片描述

7 class template 类模板

class template,类模板

在设计一个类的时候,允许某个变量或者参数的类型由使用者任意指定,那么就可以把这个类称为模板类,或者叫类模板。

在这里插入图片描述

8 function template 函数模板

function template,函数模板

在使用时,不用指明参数的type,编译器会进行实参推导

在这里插入图片描述

9 member template 成员模板

member template 成员模板

在标准库中的构造函数中会出现大量的member template,为的是让构造函数更有弹性一些,比如用派生类来初始化基类。

template<class T1, class T2>
struct pair{typedef T1 first_type;typedef T2 second_type;T1 first;T2 second;pair(): first(T1()), second(T2()) {}pair(const T1& a, const T2& b): first(a), second(b) {}#ifdef __STL_MEMBER_TEMPLATES	template<class U1, class U2>  // 成员模板pair(const pair<U1, U2>& p): first(p.first), second(p.second) {}#endif
};

下面以鲫鱼继承鱼类,麻雀继承鸟类来展示成员函数。

在这里插入图片描述

把一个鲫鱼和麻雀构成的pair,放进一个鱼类和鸟类构成的pair,这个是可以的。

class Base1 {};
class Derived1: public Base1 {};class Base2 {};
class Derived2: public Base2 {};pair<Derived1, Derived2> p;
pair<Base1, Base2> p2(p);pair<Base1, Base2> p2(pair<Derived1, Derived2>()); //把一个派生类1和派生类2构成的pair,放进一个基类1和基类2构成的pair,反过来不可以
template<typename _Tp>
class shared_ptr: public __shared_ptr<_Tp>
{template<typename _Tp1>explicit shared_ptr(_Tp1* __p): __shared_ptr<_Tp>(__P) {}
};Base* ptr = new Derived1;  // up-cast 向上转型是可以的shared_ptr<Base1> sptr(new Derived1);

智能指针模拟向上转型:可以用派生类来初始化基类

在这里插入图片描述

10 specialization 模板特化

specialization 模板特化:限定模板实现的具体类型,比如下面指定hash的类型为char,int和long。

template<class Key>
struct hash {};// 特化
template<>
struct hash<char> {size_t operator()(char x) const {return x;}
};template<>
struct hash<int> {size_t operator()(int x) const {return x;}
};template<>
struct hash<long> {size_t operator()(long x) const {return x;}
};

使用过程如下:

cout << hash<long>()(1000);

在这里插入图片描述

11 模板偏特化

模板偏特化——个数的偏

模板中可以指定某些参数为特定类型。

在这里插入图片描述

模板偏特化——范围的偏

从指向任意类型T,变成指向任意类型的指针*T,范围变小了。

在这里插入图片描述

12 模板模板参数

template template parameter,模板模板参数

可以让模板参数它本身是个类模板。下图中第二个参数为模板模板参数Container,它接收第一个模板参数来实例化自己,比如接收下面T类型。

template<typename T, template<typename T> class Conatainer>
class XCls
{
private:Container<T> c;
public:...
}

在这里插入图片描述

13 关于C++标准库

Containers、Iterators、Algorithms、Functors的等使用,有另外一门课进行剖析。

14 三个主题 variadic templates等

variadic templates 可变参数模板

使用3个点…来表示

template<typename T, typename... Types>void print()
{}
void print(const T& firstArg, const Types&... args)
{cout << firstArg << endl;print(args...);
}

在这里插入图片描述

auto 用法:自动推导变量类型

之前的用法

list<string> c;
list<string>::iterator ite;
ite = find(c.begin(), c.end(), target);

C++11的用法

list<string> c;
auto ite = find(c.begin(), c.end(), target);

ranged-base for

能传引用就传引用,速度快。

vector<double> vec;for(auto elem: vec) {cout << elem << endl;
}for (auto& elem: vec) { // 改变原来的数据,要传引用&elem *= 3;
}

在这里插入图片描述

15 reference

int x = 0;

pointer to interger: int *p = &x;

reference to interger: int& r = x; r不是指针,r代表x, x的地址在哪,r的地址就在哪。 但是底层实现的时候使用指针实现的。

如果 int x2 = 5; r = x2;由于r已经代表了x,它不能重新代表其他的东西,经过r = x2;之后,r和x都变成了5.

在这里插入图片描述

reference引用的常见用途

在这里插入图片描述

16 复合&继承关系下的构造和析构

单独的继承关系、符合关系的继承与析构请参加我的笔记C++面向对象高级编程(侯捷)笔记2中关于11 组合与继承的部分。

这里记录继承+组合关系下的构造和析构

构造由内而外

Derived的构造函数首先调用Base的默认构造函数,然后调用Component的默认构造函数,然后执行自己。

析构由外而内

Derived的析构函数首先执行自己,然后调用Component的析构函数,然后调用Base的析构函数。

在这里插入图片描述

17 (对象模型)关于vptr和vtbl,虚指针和虚表

下面开始谈Object Model的内容。

虚指针vptr和虚表vtbl

virtual function虚函数有两个步骤来支持:

  1. 每一个class产生出一堆指向virtual functions的指针,放在virtual table(vtbl)中。
  2. 每一个class object被添加了一个指针,指向相关的virtual table。通常这个指针被称为vptr。vptr的设置和重置都由每个class的构造函数、析构函数和拷贝赋值运算符自动完成。

参考:深度探索C++对象模型

继承中,子类的对象里面有父类的成分

调用虚函数的过程,通过vptr得到vtbl,然后查找表中的第n个函数

(*(p->vptr[n]))(p);(*p->vptr[n])(p);

在这里插入图片描述

18 (对象模型)关于this

对象模型object model:关于this

动态绑定的三个条件:

  1. 通过指针调用
  2. 指针有向上转型的动作
  3. 调用虚函数

在这里插入图片描述

编译器对动态绑定动作:

this->Serialize();

编译成下面这种形式:虚指针指向虚表,调用特定的虚函数

(*(this->vptr)[n])(this);

19 (对象模型)关于Dynamic Binding

对象模型:关于Dynamic Binding

静态绑定:直接调用汇编的call指令,跳转到函数地址。

B b;
A a = (A)b;
a.vfunc1(); // 静态绑定,直接call vfunc的地址

在这里插入图片描述

动态绑定:虚指针查虚表得到虚函数的地址,进行调用。

A* pa = new B;  // 向上转型
pa->vfunc1();

在这里插入图片描述

后记

从2024年1月1日开始,截至2024年1月4日,共花费4天,学习完C++面向对象高级编程(上)和C++面向对象高级编程(下),其中后者的标题为C++程序设计兼谈对象模型。

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

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

相关文章

【计算机毕业设计】SSM企业OA管理系统

项目介绍 本项目包含管理员与普通员工两种角色&#xff0c; 管理员角色包含以下功能&#xff1a; 岗位管理,部门管理,工龄奖金管理,员工管理,考勤管理,工资查询,职称管理,统计图表,工资项管理,管理员登录等功能。 员工角色包含以下功能&#xff1a; 个人信息管理,工资详情…

基于PHP的花店管理系统

有需要请加文章底部Q哦 可远程调试 基于PHP的花店管理系统 一 介绍 此花店管理系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为用户和管理员。(附带参考设计文档) 技术栈&#xff1a;phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 …

[蓝桥 2023 ]三带一

问题描述 小蓝和小桥玩斗地主&#xff0c;小蓝只剩四张牌了&#xff0c;他想知道是否是“三带一”牌型。 所谓“三带一”牌型&#xff0c;即四张手牌中&#xff0c;有三张牌一样&#xff0c;另外一张不与其他牌相同&#xff0c;换种说法&#xff0c;四张手牌经过重新排列后&am…

使用jmeter从0开始完成性能测试

使用JMeter从0开始完成性能测试 介绍 在软件开发过程中&#xff0c;性能测试是一项关键任务&#xff0c;它可以帮助我们评估系统在不同负载条件下的性能表现&#xff0c;发现潜在的性能瓶颈。JMeter是一款功能强大且易于使用的性能测试工具&#xff0c;它可以帮助我们完成各种…

网络故障排查和流量分析利器-Tcpdump命令

Tcpdump是一个在Unix/Linux系统上广泛使用的命令行网络抓包工具。它能够捕获经过网络接口的数据包&#xff0c;并将其以可读的格式输出到终端或文件中。Tcpdump是一个强大的命令行工具&#xff0c;能够捕获和分析网络数据包&#xff0c;为网络管理员和安全专业人员提供了深入了…

手写视频裁剪框

<!-- 截取框 --><divv-show"isShow"class"crop-box":style"{width: cropWidth px,height: cropHeight px,left: cropX px,top: cropY px,}"ref"cropBox"mousedown"startInteraction"><!-- 内容在这里 --…

mysql 单表 操作 最大条数验证 以及优化

1、背景 开车的多年老司机&#xff0c;是不是经常听到过&#xff0c;“mysql 单表最好不要超过 2000w”,“单表超过 2000w 就要考虑数据迁移了”&#xff0c;“你这个表数据都马上要到 2000w 了&#xff0c;难怪查询速度慢”。 2、实验 实验一把看看… 建一张表 CREATE TABL…

Java BIO、NIO、AIO、Netty知识详解(值得珍藏)

1. 什么是IO Java中I/O是以流为基础进行数据的输入输出的&#xff0c;所有数据被串行化(所谓串行化就是数据要按顺序进行输入输出)写入输出流。简单来说就是java通过io流方式和外部设备进行交互。 在Java类库中&#xff0c;IO部分的内容是很庞大的&#xff0c;因为它涉及的领…

[Ray Tracing: The Rest of Your Life] 笔记

前言 开年第一篇博客~ 整理了三四个小时才整理完orz。 这一部分是光线追踪三部曲的最后一部&#xff0c;主要介绍了蒙特卡洛积分、重要性采样等内容。场景上没有什么大的改变&#xff0c;基本上就是在Cornell Box中渲染的&#xff0c;本篇主要在加速收敛&#xff0c;提升渲染效…

Docker 安装Mysql

目录 Docker Mysql安装 ✨安装和配置mysql ✨远程连接mysql远程连接 MySQL 是世界上最流行的开源数据库。根据 DB-Engines的调查数据&#xff0c;MySQL 是第二受欢迎的数据库&#xff0c;仅次于 Oracle 数据库。MySQL在过去由于性能高、成本低、可靠性好&#xff0c;已经成…

五、HTML 标题

在 HTML 文档中&#xff0c;标题很重要。 一、HTML 标题 标题&#xff08;Heading&#xff09;是通过 <h1> - <h6> 标签进行定义的。<h1> 定义最大的标题。 <h6> 定义最小的标题。 <h1>这是一个标题。</h1> <h2>这是一个标题。&l…

分类预测 | Python实现基于SVM-RFE-LSTM的特征选择算法结合LSTM神经网络的多输入单输出分类预测

分类预测 | Python实现基于SVM-RFE-LSTM的特征选择算法结合LSTM神经网络的多输入单输出分类预测 目录 分类预测 | Python实现基于SVM-RFE-LSTM的特征选择算法结合LSTM神经网络的多输入单输出分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 基于SVM-RFE-LSTM的特征…

bootstrap5实现宠物商店网站 Cat-Master

一、需求分析 宠物商店网站是指专门为宠物商店或宠物用品商家而建立的在线平台。这种网站的功能通常旨在提供以下服务&#xff1a; 产品展示&#xff1a;宠物商店网站通常会展示宠物食品、玩具、床上用品、健康护理产品等各种宠物用品的图片和详细信息。这样&#xff0c;潜在的…

MybatisPlus—快速入门

目录 1.使用MybatisPlus的基本步骤 1.1引入MybatisPlus的起步依赖 1.2 定义Mapper 2.MybatisPlus常用注解 2.1 TableName 2.2 TableId 2.3 TableField 2.4 小结 3. 常用配置 4. 总结 1.使用MybatisPlus的基本步骤 1.1引入MybatisPlus的起步依赖 MyBatisPlus官方提…

安徽省暨合肥市“希望工程·梦想计划”小盖茨机器人捐赠启动仪式举行

1月5日&#xff0c;安徽省暨合肥市“希望工程梦想计划”小盖茨机器人捐赠启动仪式在合肥市一六八玫瑰园学校东校区举行。共青团安徽省委副书记叶征&#xff0c;北京儒布特教育科技有限公司董事牛俊明&#xff0c;北京儒布特教育科技有限公司市场总监高进&#xff0c;安徽省青基…

基于JavaWeb+SSM+Vue四六级词汇微信小程序系统的设计和实现

基于JavaWebSSMVue四六级词汇微信小程序系统的设计和实现 源码获取入口KaiTi 报告Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 源码获取入口 KaiTi 报告 &#xff08;1&#xff09;课题背景 伴随着社会的快速发展, 现代社…

【ASP.NET Core 基础知识】--环境设置

一、简介 1.1 .NET Core SDK 概述 .NET Core SDK&#xff08;Software Development Kit&#xff09;是Microsoft推出的一个开源跨平台框架&#xff0c;用于开发和部署.NET应用程序。它是.NET Core平台的核心组件之一&#xff0c;为开发者提供了在多个操作系统上构建高性能、可…

WPF 使用矢量字体图标

矢量字体图标 在WPF项目中经常需要显示图标&#xff0c;但是项目改动后&#xff0c;有时候需要替换和修改图标&#xff0c;这样非常麻烦且消耗开发和美工的时间。为了快速开发项目&#xff0c;节省项目时间&#xff0c;使用图标矢量字体图标是一个非常不错的选择。 矢量字体图标…

使用爬虫爬取热门电影

文章目录 网站存储视频的原理M3U8文件解读网站分析代码实现 网站存储视频的原理 首先我们来了解一下网站存储视频的原理。 一般情况下&#xff0c;一个网页里想要显示出一个视频资源&#xff0c;必须有一个<video>标签&#xff0c; <video src"xxx.mp4"&…

大学生搜题软件,未来可期吗?

作为一家专注于软件开发的公司《智创有术》&#xff0c;我们致力于为客户提供创新、高效和可靠的解决方案。通过多年的经验和专业知识&#xff0c;我们已经在行业内建立了良好的声誉&#xff0c;并赢得了客户的信任和支持。 支持各种源码&#xff0c;网站搭建&#xff0c;APP&a…