草庐IT

c++对象模型

chenglixue 2023-04-15 原文
  • C语言中,数据与处理数据的操作(函数)是分开声明的,这种程序方法被称为程序性的;而在c++中,则是使用abstract data type(ADT)或class hierarchy的数据封装
  • c++对于结构体和函数(不包含virtual和non-inline)的封装并没有增加布局成本,对于C++而言,在布局以及存取时间上主要的额外负担是由virtual引起
    • virtual function
    • virtual base class

The c++ Object Model

  • c++中,有两种class data members:static and nonstatic,和三种class member functions:static、non-static and virtual

  • 现有以下class声明:

    class Point
    {
    public:
        Point(float xval);
        virtual ~Point();
        
        float x() const;
        static int PointCount();
        
    protected:
        virtual ostream& print( ostream & os ) const;
        
        float _x;
        static int _point_count;
    }
    
  • 此 class 可以通过三种object models表示

A Simple Object Model

  • 一个object是一系列slots,每一个slots指向一个member,Members按其声明顺序,各被指定一个slot。每一个data member or function member都有自己的一个slot

  • 目的:尽量减低C++ complier的设计复杂度,但会损失空间和执行器的效率

    • 意义:应用到c++的"指向成员的指针"观念中

A Table-driven Object Model

  • 将所有members的信息抽离出来放在一个member data table 和 一个member function table中,而class则含有指向这两个table的pointer

  • 意义:成为virtual function的一个方案

The c++ Object Model

  • 此模型从A Simple Object Model派生而来,并对内存空间和存取时间优化
  • Nonstatic data members被配置于每一个class object内,static data members、Static function members、 nonstatic function members则被存放于个别的class object外。而用virtual functions来支持此model:
    • virtual tabel(vtbl)中存放一些指向由class生成的virtual functions的pointer
    • 每个class object安插一个指针(vptr),此指针指向相关的virtual table。而vptr的setting 和 resetting都有class里的constructor、destructor、copy assignment运算符自动完成。每个class关联的type_info object(支持runtime type identification,RTTI)亦由virtual table指出,通常放于表格中的第一个slot
  • 优点:空间和存取时间效率高
  • 缺点:若应用程序本身未改变,而class内的nonstatic data members有所修改,则应用程序代码需重新编译

  • c++支持单一继承、多重继承、虚拟继承。虚拟继承中,base class不管在继承串链中被派生多少次,永远只存在一个实例subobject

A Keyword Distinction

  • C++为了维护和C之间的兼容性,为此付出了很多牺牲
int (*pq) ();
  • 当语言无法区分此函数是declaration还是invocation时,需要一个超越语言范围的规则,此规则会将此函数判断为declaration
  • struct的一个合理用途:将class object某个数据做封装,达到与C的兼容的空间布局,只有composition才支持
  • template并没有兼容struct

An Object Distinction

  • c++程序设计模型支持三种programming paradigms
    • procedural model
    • abstract data type model
    • object-oriented model
  • object-oriented model中,被指定的object的真实类型在每个特定执行点前无法解析,只有通过pointer 和 reference才能完成;相反,abstract data type model中,所处理的是一个固体且单一类型的实例,真实类型早在编译时期就已定义,因此速度更快且空间排布更紧凑,但没有弹性
  • c++用三种方法支持多态:
    • 经由一组隐式转化。如把derived class pointer转化为public base type的pointer
    • 经由virtual function机制
    • 经由dynamic_cast和typeid运算符
  • 多态主要用途:由一个共同的接口影响类型封装,此接口通常被定义在抽象的base class
  • class object所需的内存大小:
    • nonstatic data members的总和大小
    • 任何由于alignment(将数值调整到某数倍数)的需求而padding的空间
    • 支持virtual产生的额外负担

The Type of a Pointer

  • "指针类型"告诉编译器如何解释目的地址中的内容和大小,这也是为什么pointer和reference支持多态
  • 我们并不知道void*指针涵盖的地址空间,因此void*的指针只含有一个地址,且不能操作所指向的object
  • cast本质上是编译器指令,它并不改变指针所含的地址,而只影响"所指内存的大小和其内容"的解释方式

Adding Polymorphism

class A
{
    public:
    	virtual action1();
    ...
}


class B : public A
{
    //以下皆为B独有
    public:
    	...
    	void rotate();
    
    protected:
    	enum action2 {...};
    	int n;
}

B b;
A* p1 = &b;
B* p2 = &b;
  • 显然,我们并不不能用p1处理A以外的members,唯一方法是通过virtual

    //以下都可行
    (static_cast<B*> (p1))->n;
    
    if( B*p3 = dynamic_cast<B*>(p1) )	//此为run-time operation,成本较高
        p3->n;
    
p1->action1()
  • p1将在编译器决定以下两点:
    • 固定的可用接口
    • 此接口的access level
B b;
A a1 = b;	//造成sliced

a1.action1();	//调用A中的
  • 为什么a1中的vptr不会指向b的virtual table?
    • 编译器需确保若object含有一个或一个以上的vptrs,这些vptrs内容不会被base class object初始化或改变
  • 为什么action1()依旧是调用的A的?
    • 多态并不适用于直接存取objects

有关c++对象模型的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  4. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  5. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  6. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  7. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  8. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  9. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  10. ruby-on-rails - 未在 Ruby 中初始化的对象 - 2

    我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调

随机推荐