首页 > 编程语言 >C++对象模型

C++对象模型

时间:2023-11-05 12:44:06浏览次数:37  
标签:rotate 对象 模型 object ZooAnimal C++ za 编译器 class

思考:对于实现平面一个点的参数化。C++的class封装看起来比C的struct更加的复杂,是否意味着产生更多的开销呢?

实际上并没有,类的封装不会产生额外的开销,其实,C++中在布局以及存取上的额外开销是virtual引起的。

C++对象模式

在C++中,有两种class data members:静态成员和非静态成员。有三种class member functions:静态的,非静态的以及虚函数

C++对象模型

Nonstatic datamembers 被配置于每一个class object之内。static data members则被存放在个别的class object之外。

static 和nonstatic function members也被存放在class object之外(仅一份)

virtual fuction:每一个class产生一堆指向virtual table(vtbl)中;每一个class object被安插一个指针,vptr指向相关的virtual table

(图示)
file

关于继承

继承关系也可指定为虚拟(也就是共享)

(图示)
file

在虚拟继承的情况下,base class不管在继承串链中被派生多少回,永远只存在一个实例(subobject)

(图示)
file

对象模型如何影响程序

(图示)
file

对象的差异

程序模型(类C)

char boy[] = "Danny";
char *p_son;
...
p_son = new char [strlen(boy) + 1];
strcpy(p_son,boy);
...
if(!strcmp(p_son,boy))
    take_to_disneyland(boy)

抽象数据类型(ADT)

string girl = "Anna";
string daughter;
...
//string :: operator = ()
daughter = girl;
//string::operator==()
if(girl == daughter)
   take_to_disneyland(girl);

面对对象编程

void
check_in(Library_materials *pmat)
{
if(pmat->late() )
    pmat->fine();
pmat->check_in();
if(Lender *plend = pmat->reserved())
   pmat->notify(plend);
}

多态实现

在C++中,多态只存在于一个个的public class体系中

有这样三种多态支持:

经由一组隐式的转化操作。例如把一个derived class指针转化为一个指向public base type的指针;

shape *ps = new circle();

经由virtual fuction机制

ps->rotate();

经由dynamic_cast和typeid运算符;

if(circle pc = dynamic_cast<circle>(ps))..

思考:需要多大内存才能够表现一个class object?

非静态数据成员(non-static data members):非静态数据成员是每个类对象都需要独立分配的,所以其大小需计算在内。

虚函数表指针(vptr):如果类含有虚函数,则需要一个指针指向虚函数表,用于动态绑定。这个指针的大小通常是机器字长,比如64位系统为8字节。

内存对齐填充(padding):为了优化内存访问效率,编译器会在类成员之间插入内存对齐填充。

其他系统占用空间:除了类自身需要的空间外,一些编译器和系统会在类对象中预留一些额外空间,例如运行时类型信息(RTTI)。

所以一个类对象所需内存的计算公式概略为:对象内存 = 非静态数据成员大小总和 + (含虚函数则加上vptr指针大小) + 填充大小 + 其他系统占用大小

其中除了非静态数据成员外,其他部分大小在不同系统和编译器下可能有所不同。

一个更准确的计算对象大小的方法是:在程序中使用sizeof运算符,它会返回这个平台下该类对象的确切字节大小。

注意:

类中静态数据成员(static data member)与对象的内存大小无关。

静态数据成员不属于类的任何一个对象,只会在程序的整个生命周期内有一份内存拷贝存在。

所以静态数据成员不会影响每个类对象实例的内存需求。
指针的类型

例子:

ZooAnimal  *px;
int *pi;
Array<string>*pta;

从内存上面看,这几个指针没有什么区别,大小是一个机器地址。(word)

但是其实,“指针类型”会教导编译器如何解释某个特定地址中的内存内容以及大小。

(图示)
file
进一步探讨:

Bear b;
ZooAnimal za=b; //译注:这会引起切割(sliced)
//调用 ZOOAnimal::rotate()
za.rotate();

为什么rotate所调用的是ZooAnimal实例而不是Bear实例?此外,如果初始化函数(译注:应用于上述assignment操作发生时)将一个object内容完整拷贝到另个object去,为什么za的vptr 不指向Bear的virtual table?

ZooAnimal za = b;这行代码中,使用基类ZooAnimal的引用或指针初始化时,编译器会:

  1. 为za分配一个ZooAnimal类型的空间
  2. 把b对象中的ZooAnimal部分的数据拷贝过来

也就是说,这个赋值操作生成了一个新的ZooAnimal对象,它只包含了原b对象中的ZooAnimal部分的数据和函数,丢失了b作为Bear的额外信息。

然后za调用rotate()时,编译器根据静态类型(ZooAnimal)调用ZooAnimal::rotate(),而不是动态类型Bear::rotate()。

如果想保留全部信息,可以使用指针或引用:cpp Bear b; ZooAnimal* za = &b; za->rotate(); // 调用Bear::rotate()

或者使用动态绑定:cpp Bear b; ZooAnimal& za = b; za.rotate(); // 调用Bear::rotate()

编译器在将一个class object指定给另一个class object之间做出仲裁,编译器必须保证如果某个object含义一个或者以上的vptrs,那些vptrs不会被base class 改变。

补充:

当一个base class object 被直接初始化为(或是被指定为)一个 derived classobject 时,derivedobject 就会被切(sliced)以塞入较小的 base type 内存中,derivedtype将没有留下任何蛛丝马迹。多态于是不再呈现,而一个严格的编译器可以在编译时期解析一个“通过此object而触发的virtualfunction调用操作”,因而回避virtual机制。如果virtualfunction 被定义为inline,则更有效率上的大收获。

本文由博客一文多发平台 OpenWrite 发布!

标签:rotate,对象,模型,object,ZooAnimal,C++,za,编译器,class
From: https://www.cnblogs.com/xiaocrblog/p/17810409.html

相关文章

  • 实验2 类和对象_基础编程2
    实验任务1demo1.dev方法一#ifndefT_H#defineT_H#include<iostream>#include<string>usingnamespacestd;//类T的声明classT{public:T(intx=0,inty=0);//带有默认形值的构造函数T(constT&t);//复制构造函数T(T&&......
  • python用支持向量机回归(SVR)模型分析用电量预测电力消费|附代码数据
    全文链接:http://tecdat.cn/?p=23921最近我们被客户要求撰写关于支持向量机回归的研究报告,包括一些图形和统计输出。本文描述了训练支持向量回归模型的过程,该模型用于预测基于几个天气变量、一天中的某个小时、以及这一天是周末/假日/在家工作日还是普通工作日的用电量关于支持......
  • Spectron: 谷歌的新模型将语音识别与语言模型结合进行端到端的训练
    Spectron是谷歌Research和VerilyAI开发的新的模型。与传统的语言模型不同,Spectron直接处理频谱图作为输入和输出。该模型消除归纳偏差,增强表征保真度,提高音频生成质量。它采用预训练的语音编码器和语言解码器,提供文本和语音的延续。但是频谱图帧生成比较费时并且无法并行文本和......
  • c++实现排序算法
    排序算法选择排序#include<iostream>#include<cmath>usingnamespacestd;intmain(){ intn,i,j,a[2000]; boolt; cin>>n; for(i=1;i<=n;i++) cin>>a[i]; for(i=1;i<n;i++) for(j=i+1;j<=n;j++) if......
  • 面向对象和面向过程
    面向对象,里面的“面向”是什么意思呢,“面向”的意思就是面对着,面向对象,就是你看到的都是对象,比如你做一顿午饭,面向对象的就是:盖浇饭,茶水面向过程的话就是:炒饭+米饭+炒菜 所以这里的面向,是程序员面向,从程序员视角看到的世界,如果看到的是一个个对象,那就是面向对象,如果看到的是一......
  • java 类和对象以及封装
    封装对象代表什么,就得封装对应的数据,并提供数据对应的行为......
  • Windows系统 C/C++程序编译后首次执行时间很长 断网则正常执行 的解决方法
    Windows系统C/C++程序编译后首次执行时间很长断网则正常执行的解决方法问题描述运行环境:Win10、Win11或其他Win环境。在各类IDE(包括但不限于VC6/VisualStuido等)编译任意C/C++源码(无论该程序有多简单),首次运行时间异常地长,即在黑窗口无任何输出。等待一段时间后有程序正......
  • python面向对象-学习笔记(八、综合案例)
    计算器,实现一些基本的操作,加减乘除运算,以及打印结果操作点击查看代码importwin32com.clientclassCaculator:#装饰器私有def__check_num_zsq(func):definner(self,n):ifnotisinstance(n,int):raiseTypeError("......
  • cout对象在全局只能拥有一个
    1.问题在学习符号重载的过程中,有一个想法std::ostream&operator<<(std::ostream&cout,Person&p);中std::ostream&cout能不能不使用引用,而使用std::ostreamcout?但是报错:Calltodeletedconstructorof'std::ostream'(aka'basic_ostream')2.解决cout作......
  • Java学习—对象和类
    对象&类对象:对象是类的一个实例(对象不是找个女朋友),有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。类:类是一个模板,它描述一类对象的行为和状态。java命名约定的优点通过使用标准的Java命名约定,您可以使自己和其他程序员更容易阅读代码。Jav......