对象

封装成本

  • C++所有对象之间共享成员函数

  • 每个非内联函数只产生一个函数实体

  • 每个内联函数将在每个使用内联函数的地方都拥有一份副本

内联函数这个特征很好理解,毕竟内联函数是被复制到使用内联函数的地方,而不是按地址调用

C++ 封装后的成本主要是由虚有函数和虚有基类造成的:

  • 虚有函数用于支持运行时绑定

  • 虚有基类用来实现 多次出现在继承体系中的基类拥有单一、共享的实体

此外,子类与非第一基类之间的类型转换也会造成额外成本

对象模型

C++根据对数据成员(静态数据成员、非静态数据成员)和成员函数(静态成员函数、非静态成员函数)的处理方式不同,构成了不同的对象模型:

简单对象模型

简单对象模型(Simple Object Model)中对象中只保存成员指针(数据成员指针和成员函数指针),此种情况下 对象的大小 = 指针的大小 x 指针的数量

image

该对象模型降低了编译器的设计复杂度,代价是空间和执行期的效率。

这个模型并没有被应用于实际,但是为 指向成员的指针 提供了概念模型。

表格对象模型

表格对象模型(Table-driven Object Model)中,将数据成员和成员函数各自储存在一张表格中,对象则持有这两张表格的指针。数据成员表格中保存着数据成员的实体,而成员函数指针则保存着成员函数的指针。

image

这个模型没有被应用于实际,但是为 虚函数 提供了概念模型

C++对象模型

C对象模型(C Object Model)描述如下:

  • 非静态数据成员储存到对象中

  • 静态数据成员储存到对象之外

  • 静态成员函数和非静态成员函数储存于对象之外

  • 虚函数表的指针储存于对象之中

虚函数的支持方法如下:

  1. 建立虚函数表( vtbl (virtual table) )储存指向虚函数的指针

  2. 在对象中建立指向vtbl的指针(vptr)。vptr的初始化和销毁由构造函数、析构函数、复制构造函数自动完成。

  3. 对象关联的 类型信息对象 (type_info object) 被储存到vtbl的首部(通常情况下)

image

该模型的优点是空间和效率比较好,但是一旦类的非静态数据成员发生改变,整个软件代码必须要重新编译

C++继承模型

  1. 简单对象模型的继承模型

    简单对象模型可以通过添加父类指针来储存基类,优点是子类大小与父类无关,但是带来了空间和效率的开销。

  2. 基于表格的继承模型

    通过构造 基类表 (base table) 可以实现另一种继承模型,其特点为:

    • 基类表中包含指向基类的指针(多继承时包含多个基类指针)

    • 每个类对象都包含一个 指向基类表的指针(bptr)

    其优点为无需更改类对象就可以更改基类,缺点是带来了储存空间和效率上的负担。

    image

C++编程范型

C++支持三种编程范型:

  1. 过程式编程

    例如: +

const 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);
  1. 抽象数据模型(ADT)

    抽象数据模型为用户提供借口,及内部计算过程隐而不提: +

string girl = "Anna"
string daugher;
...
daugher = girl; // operator=()
...
if(girl == daugher) // operator==()
    take_to_disneyland(girl);
  1. 面向对象模型(Object-Oriented model)

    面向对象模型通过抽象基类向外部提供接口,子类对接口进行实现。 +

class Human{
public:
    virtual void eat() = 0;
};

class Chinese: public Human{
public:
    void eat() override {
        cout<<"Chinease eat"<<endl;
    }
};

class American: public Human{
public:
    void eat() override {
        cout<<"American eat"<<endl;
    }
};

+

Important

OO模型的多态依赖于指针(或引用)的间接处理,若使用非指针类型进行类型转换,很可能会丢失信息。因此,使用OO范型的话尽可能使用指针(或引用)。

尽量使用一种范型,而不是混用范型

Last moify: 2024-11-22 02:16:03
Build time:2025-07-18 09:41:42
Powered By asphinx