《深度探索c++对象模型》第七章笔记

news2024/10/6 10:42:31

非原创,在学习

7 站在对象模型的尖端 On the Cusp of the Object Model

这一章讨论三个著名的C++语言扩充性质,它们都会影响CH+对象。它们分别是 template、exception handling (EH)和runtime type identification (RTTI)

模版、异常、通过运行时类型识别

7.1 template

下面是有关template的三个主要讨论方向:

1. templatc的声明。基本上来说就是当你声明一个template class、templateclass member function等等时,会发生什么事情。

2.如何“具现( instantiates)”出class object以及inline nonmember,以及member template functions,这些是“每一个编译单位都会拥有一份实体”的东西。

3.如何“具现( instantiates)”出nonmember以及member template functions以及static template class members,这些都是“每一个可执行文件中只需要一份实体”的东西。这也就是一般而言template所带来的问题。

下面是一个template function;:

namespace Test24 {
    template<class Type>
    Type min(const Type& t1, const Type& t2) {
        // ...
    }

    void test()
    {
        min(1.0, 2.0);
    }
}

于是Type 被绑定为double 并产生min()的一个程序文字实体(并适当施以“mangling”手术,给它一个独一无二的名称),其中tl 和 t2的类型都是double。

Template的“具现”行为( Template Instantiation )

考虑下面的template Point class:

namespace Test25
{
    template <class Type>
    class Point
    {
    public:
        enum Status
        {
            unallocated,
            normalized
        };
        Point(Type x = 0.0, Type y = 0.0, Type z = 0.0);
        ~Point();

        void *operator new(size_t);
        void operator delete(void *, size_t);

        // ...

    private:
        static Point<Type> *freeList;
        static int chunkSize;
        Type _x, _y, _z;
    };
}

枚举和类型没有关系,但是不能这样写:

Point::Status s;         // error

必须这样写:

Point<float>::Status s;

同样的道理,freeList和chunksize也得这样写。

如果定义一个指针,指向特定的实体,像这样:

Point<float>* ptr = 0;

这一次,程序中什么也没有发生。为什么呢?因为一个指向class object的指针,本身并不是一个 class object,编译器不需要知道与该class有关的任何members的数据或object布局数据.所以将“Point的一个float实体”具现也就没有必要。

如果不是指针而是reference呢

const Point<float> &ref = 0;

是的,它真的会具现出一个“Point的 float实体”来.这个定义的真正语意会被扩展为:

// 内部扩展
Point<float> temporary(float(0));
const Point<float>& ref = temporary;

为什么呢?因为reference 并不是无物( no object)的代名词.0被视为整数,必须被转换为以下类型的一个对象。

然而,member functions(至少对于那些未被使用过的)不应该被“实体”化,只有在 member functions被使用的时候,C++ Standard才要求它们被“具现”出来。当前的编译器并不精确遵循这项要求。之所以由使用者来主导“具现"( instantiantion)规则,有两个主要原因:

1.空间和时间效率的考虑。如果class中有100个member functions,但你的程序只针对某个类型使用其中两个,针对另一个类型使用其中五个,那么将其它193个函数都“具现”将会花费大量的时间和空间。

2.尚未实现的机能。并不是一个template具现出来的所有类型就一定能够完整支持一组member functions所需要的所有运算符。如果只“具现’那些真正用到的member functions,template就能够支持那些原本可能会造成编译时期错误的类型( types) .

Template 的错误报告(Error Reporting within a Template)

明显的错误:

namespace Test26
{
    template <class T>
    class Mumble
    {
        // $、t被初始化为1024,不确定对不对、tt是成员变量,_t不是
        public$ : Mumble(T t = 1024) : _t(t)
        {
            // != 需要重载
            if (tt != t)
            {
                // ex
                throw ex ex;
            }
        }

    private:
        T tt;
    }                // 没有;结尾
}

运行

按报错修改:

这句是正确的???

if (tt != t)

目前的编译器,面对一个template声明,在它被一组实际参数具现之前,只能施行以有限的错误检查。template中那些与语法无关的错误,程序员可能认为十分明显,编译器却让它通过了,只有在特定实体被定义之后,才会发出抱怨这是目前实现技术上的一个大问题。

写模版的时候,一定一定要特别注意。

Template 中的名称决议方式(Name Resolution within a Template)

必须能够区分以下调种意义。一种是C+t Standard所谓的“scope of thetemplate definition”,也就是“定义出template”的程序。另一种是C++ Standard所谓的“scope of the iemplase instantiation”,也就是“具现出template”的程序。

第一个是模版程序

namespace Test27
{
    // scope of the template definition
    extern double foo(double);
    template <class type>
    class ScopeRules
    {
    public:
        void invariant()
        {
            _member = foo(_val);
        }

        type type_dependent()
        {
            return foo(_member);
        }

        // ...

    private:
        int _val;
        type _member;
    };

}

第二个是模版实例化程序

extern int foo(int);
// ...
ScopeRules<int> sr0;

在ScopeRules template中有两个foo()调用操作。在“scope of template definition”中,只有一个foo()函数声明位于scope 之内。然而在“scope of template instantiation”中,两个foo()函数声明都位于scope 之内。如果我们有一个函数调用操作:

sr0.invariant();

那么,在 invariant(中调用的究竟是哪一个foo()函数实体呢?

_mamber = foo(_val);

在调用操作的那一点上,程序中的两个函数实体是:

// scope of the template declaration
extern double foo (double);
// scope of the template instantiation
extern int foo (int);

测试一下

namespace Test27
{
    // scope of the template definition
    extern double foo(double) {
        std::cout << "extern double foo(double)" << std::endl;
    }
    template <class type>
    class ScopeRules
    {
    public:
        void invariant()
        {
            _member = foo(_val);
        }

        type type_dependent()
        {
            return foo(_member);
        }

        // ...

    private:
        int _val;
        type _member;
    };

    extern int foo(int) {
        std::cout << "extern int foo(int)" << std::endl;
    }
    // ...
    ScopeRules<int> sr0;

    void test() {
        ScopeRules<int> sr0;
        sr0.invariant();
    }

}

int main(int argc, char **argv)
{
    Test27::test();
    system("pause");
    return 0;
}

竟然调用的是double这个(似乎和函数出现的顺序有关)

Template 之中,对于一个nonmember name 的决议结果是根据这个name 的使用是否与“用以具现出该template的参数类型”有关而决定的.如果其使用互不相关,那么就以“scope of the template declaration”来决定name。如果其使用互有关联,那么就以“scope of the template instantiation”来决定name。

另外看看“与类型相关”( type-dependent)的用法:

sr0.type_dependent();

结果

这意味着一个编译器必须保持两个scope contexts:
1. “scope of the template declaration”,用以专注于一般的 template class

2. “scope of the template instantiation”,用以专注于特定的实体。编译器的决议( resolution)算法必须决定哪一个才是适当的 scope,然后在其中搜寻适当的name.
 


 

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

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

相关文章

vite项目中使用@代表根路径

1.配置vite.config.ts import { defineConfig } from vite import vue from vitejs/plugin-vue import path from pathexport default defineConfig({plugins: [vue()],resolve: {alias:{: path.resolve(__dirname, src) }} })2.报错path和__dirname 找不到模块“path”或其相…

K8S系列文章 之 编写自动化部署K8S脚本

介绍 通过ansible脚本shell实现自动化部署k8s基础集群(v1.25.0) 部署结构 1. 通过二进制部署包镜像安装k8s集群、目录etcd节点只支持1-3个节点、最多三个etcd节点 2. 因k8s版本相对较新、需要升级内核来支持后台程序、当前版本只支持Cento7&#xff0c;内核版本(5.19.4-1.el7…

本地构建包含java和maven的镜像

目录 1.前提条件 2.下载 2.1.创建Dockerfile 3.构建镜像 参考文章 1.前提条件 本地环境需要的系统和软件 win10 Docker Desktop Powershell 图1 Win10安装Docker后&#xff0c;直接在Powershell使用Docker命令 有些Developer不习惯win10系统&#xff0c;却想要使用Lin…

使用ResponseBodyAdvice封装统一返回值

目录 ResponseBodyAdvice 接口概述 ResponseBodyAdvice 快速使用 父pom文件 pom文件 ResponseDto MyResponseBodyAdvice DemoController 结果展示 ResponseBodyAdvice 接口概述 在实际项目中&#xff0c;我们经常需要在请求前后进行一些操作&#xff0c;比如&#xf…

Cesium 实战教程 - 三种方式(CZML、nodeTransformations)修改模型节点组件属性(比例、旋转、移动等)

Cesium 实战教程 - 三种方式&#xff08;CZML、nodeTransformations&#xff09;修改模型节点组件属性&#xff08;比例、旋转、移动等&#xff09; 核心代码完整代码在线示例 关于 Cesium 设置模型组件的动作&#xff0c;之前是通过 CZML articulations 来实现的&#xff0c;…

xAI与GPT-4:探索宇宙真实本质的AI之战

xAI与GPT-4&#xff1a;AI之战 写在前面第一部分推动科学研究提升人机交互引发伦理和社会问题 第二部分模型的进一步优化跨领域合作人机融合 反AI斗士 马斯克进军AI中国的AI产业怎么样AI这把火&#xff0c;还能怎么烧&#xff1f;最后总结 北京时间7月13日凌晨&#xff0c;马斯…

加速手机充电,打开这个小技巧,让充电速度翻倍,快速充满电量

加速手机充电&#xff0c;打开这个小技巧&#xff0c;让充电速度翻倍&#xff0c;快速充满电量 通过打开这个小技巧&#xff0c;我们可以在有限的时间内快速充满手机电量&#xff0c;解决了电量不足的困扰。不再需要长时间等待充电&#xff0c;让我们能够更加便捷地使用手机&a…

微服务监控技术skywalking的部署与使用(亲测无坑)

微服务监控技术skywalking的部署与使用 1. 前期准备2. skywalking安装部署2.1 Java Agent2.2 apache/skywalking-oap-server2.3 apache/skywalking-ui 3. 项目启动4.效果展示 1. 前期准备 注&#xff1a;本篇文章采用docker部署&#xff0c;采用8.2.0版本&#xff0c;版本一定…

vue+Highcharts绘制3D饼图

效果图 一、下载highcharts插件 npm install highcharts 二、main.js全局配置插件 import Highcharts from "highcharts/highcharts"; import highcharts3d from "highcharts/highcharts-3d"; highcharts3d(Highcharts); 三、封装highcharts.vue组件 …

FreeFileSync 12.5 正式发布,文件夹比较与同步软件

导读FreeFileSync 是一款开源软件&#xff0c;适用于 Windows、macOS 和 Linux。FreeFileSync 本质是一个用于文件夹对比和同步的软件&#xff0c;它可以创建和管理所有重要文件的备份副本。FreeFileSync 不是每次都复制每个文件&#xff0c;而是确定源文件夹和目标文件夹之间的…

vue-baidu-map-3x 使用记录

在 Vue3 TypeScript 项目中&#xff0c;为了采用 标签组件 的方式&#xff0c;使用百度地图组件&#xff0c;冲浪发现了一个开源库 ovo&#xff0c;很方便&#xff01;喜欢的朋友记得帮 原作者 点下 star ~ vue-baidu-map-3xbaidu-map的vue3/vue2版本&#xff08;支持v2.0、v…

海外ASO优化之如何给应用选择正确的类别

将我们的应用程序放在Apple App Store和Google Play正确的类别中&#xff0c;不仅对按类别浏览应用的用户有帮助&#xff0c;而且能够帮助我们的应用程序获得良好排名。 1、应用程序属于多个类别的解决方案。 需要选择最能描述我们应用程序的类别&#xff0c;检查一下每个类别…

.net几行代码音乐API各排行榜 热搜 入库

对比了几家大厂的音乐API的接口 这家相对规范些 现在开始从零开始 net6敏捷开发对接 入库吧 关键技术工具和思维 1 json 生成类 2 分析类 规划表设计3 sqlsuger codefirst 生成表 4 封装get post 连接5 类映射automapper6 sqlsuger 插入数据 1 json 生成类 宇宙 第 一的…

轻量级低代码平台,快速生成应用程序及不同类型的CRM系统

私有化部署的低代码快速开发平台 无需代码或通过少量代码就可以快速生成应用程序的开发平台。 这套低代码管理后台平台可以支持多种企业应用场景&#xff0c;包括但不限于 OA系统、 CRM系统、 ERP系统、项目管理系统、进销存系统等。无论是懂技术的开发人员还是不懂技术的业务…

多通道振弦数据记录仪应用于桥梁监测

随着城市化进程的加快&#xff0c;城市桥梁的数量不断增加。对于城市交通的保障作用&#xff0c;桥梁的重要性不言而喻。而为了保障桥梁的安全&#xff0c;桥梁监测的重要性也越来越受到人们的重视。在桥梁监测中&#xff0c;多通道振弦数据记录仪的应用得到了广泛的认可和应用…

算法通关村第五关——n数之和问题解析

1. 两数之和问题 力扣第1题就是两数之和问题&#xff0c;给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那两个整数&#xff0c;并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一…

聚观早报|美团创始人王慧文退出;马斯克将直播与扎克伯格笼斗

【聚观365】8月8日消息 美团创始人王慧文退出马斯克将在X上直播与扎克伯格笼斗蚂蚁微尘故事余承东微博透露鸿蒙4新进展华为出资15亿成立地产公司 美团创始人王慧文退出 据国家企业信用信息公示系统显示&#xff0c;北京光年之外科技有限公司在近期完成工商变更&#xff0c;创…

Hadoop理论及实践-HDFS读写数据流程(参考Hadoop官网)

NameNode与DataNode回顾 主节点和副本节点通常指的是Hadoop分布式文件系统&#xff08;HDFS&#xff09;中的NameNode和DataNode。 NameNode&#xff08;主节点&#xff09;&#xff1a;NameNode是Hadoop集群中的一个核心组件&#xff0c;它负责管理文件系统的命名空间和元数据…

uni——不规则tab切换(skew)

案例展示 案例代码 <!-- 切换栏 --> <view class"tabBoxs"><view class"tabBox"><block v-for"(item,index) in tabList" :key"index"><view class"tabItem":class"current item.id&…

Vue 本地应用 记事本 v-on v-model v-for使用

vue当中如何生成列表结构&#xff1f;使用的指令是v-for&#xff0c;同时要有一个可以生成列表的数据&#xff0c;常用的是数组。记事本里面的内容并不复杂&#xff0c;所以这里使用字符串数组就行了。 获取用户输入的内容使用绑定v-model&#xff0c;双向数据绑定&#xff08…