对象模型

(2种)class data member: static nonstatic
(3种)class member functions: static nonstatic virtual

  1. 数据成员(Data Members)
类型 存储位置 生命周期 访问方式 示例
static 全局数据区(独立于对象) 程序运行期间 类名::成员名对象.成员 static int count;
non-static 对象内存中 随对象创建/销毁 对象.成员名 int value;
  1. 成员函数(Member Functions)
类型 是否依赖对象实例 能否访问非静态成员 能否被重写(override) 示例
static ❌ 不依赖 ❌ 不能 ❌ 不能 static void print();
non-static ✅ 依赖 ✅ 能 ❌ 不能(除非是虚函数) void show();
virtual ✅ 依赖 ✅ 能 ✅ 能(支持多态) virtual void draw();
类的组成部分 存储位置 说明
成员函数(非虚) 代码段(.text 区) 所有对象共享同一份函数代码,编译后固定在可执行文件中。
虚函数(virtual) 虚函数表(vtable) 存储在只读数据段(.rodata 或 .data),供所有对象共享。
静态成员变量 全局/静态数据区(.data/.bss) 独立于对象存在,程序启动时初始化。
RTTI(运行时类型信息) 只读数据段 用于 typeid 和 dynamic_cast(如果有虚函数)。

初始化,

default construct

(from C++ Standard)
当类没有任何用户声明的构造函数时,编译器确实会隐式声明一个默认构造函数。这个隐式声明的默认构造函数是inline public的。
对于Class X,如果没有任何user-declared constructor,那么会有一个default constrcutor被implicitly声明,一个被implicitly声明的default constructor将是一个trivial construcor

nontrivial default constructor

如果该类型在构造时可能分配内存、加锁、调用外部API等,那它几乎肯定是非平凡的。
如果它只是简单聚合数据(如POD类型),则可能是平凡的

如果class没有任何constructor,但是内含一个member object,而后者是default constructor,这个class的implicit default constructor就是"nontrivial",编译器需要为此class合成一个default constructor,不过合成操作只有再constructpr真正需要被调用的时候才会发生。

编译器为避免合成出多个default constructor,解决方法是把合成的deafult constructor、copy constructor、destructor、assignment copy operator都以inline的方式完成,一个inline函数有静态链接,不会被档案以外者看到,如果函数太复杂,会合成一个explicit non-line static实体

被合成的default constructor只满足编译器的需要,而不是程序的需要

user constrcutor

user所提供的constructors存在,所以不会合成新的default constructor。如果同时存在着"带有default constructors"的member class objects,那些default constructors也会被调用

have virtual function

class 继承或声明一个 virtual function
class 派生自一个继承串链,其中有一个或者更多的virtual base classes

由于缺乏user声明的constructor,编译器会详细记录合成一个default constructor的必要信息:
virtual function table : 内放class的virtual function地址
每一个class object种,一个额外的pointer member被编译,内含相关的class vtbl地址
virtual invocation会被重写

对于那些未声明的任何constructors的class,编译器会为它们合成一个default constructor,以便正确的初始化每一个class object的vptr

have virtual base class

虚基类的构造函数由最派生类直接调用
中间类(如A)对虚基类的构造调用可能被覆盖
成员变量(如j)的初始化与普通类一致,不受虚继承影响

virtual base class的实现法在不同的编译器之间有极大的差异,共同点在于必须使virtual base class在其每一个derived class object中的位置,能够在执行期间准备妥当

class X {public: int i;};
class A : public virtual X {public: int j;};
class B : public virtual X {public: double d;};
class C : public A, public B {public: int k;};

void foo(const A* pa){pa->i = 1024}

void foo(const A* pa) {pa->__vbcX->i = 1024;}

copy constructor

1 Class X {...} ; 对一个object做明确的初始化工作
X x;
X xx = x

2 object被当作参数
extern void foo(X x)

3 object被当作返回值
X
foo_bar{
X xx;
//...
return xx;
}

X::X(const X& x);
当一个class object以另一个同类实体作为初值时,上述的constructor会被调用。这可能会导致一个暂时性的class object的产生或优化代码

deafult memberwise initalizator

当class object以"相同class的另一个object"作为初值时,其内部是以所谓的default memberwise initializatior完成的
拷贝其内建的member_occurs,然后再于String member object_word身上递归实施memberwise initialization
c++ standard 把copy constructor区分为trivial和nontrivial两种,只有nontrivial的实体才会被合成于程序中,决定一个copy constructor是否为trivial的标准在于class是否展现“Bitwise Copy Semantics”

一个class不展现出"bitwise copy semantics":
1 class内含mamber object,而后者的class声明有一个copy constructor

class A {
public:
    int* ptr;
    A(const A& other) {  // 自定义拷贝构造
        ptr = new int(*other.ptr);  // 深拷贝
    }
};

2 class继承自一个base class,而后者存在一个copy constructor
3 class声明了一个或多个virtual functions
4 class派生自一个继承串链,其中有一个或者多个virtual base classes

virtual functions





virtual base class subobject

一个class object如果以另一个object作为初值,而后者有一个virtual base class subobject,那么也会使"bitwise copy semantics"失效
为了正确处理"以一个class object"作为另一个class object的初值,必须合成出一个copy constructor

explicit initialization

必要的程序转化分两段:
1 重写每一个定义,其中的初始化操作会被剥除
2 class的copy constructor调用操作会被安插进去

参数初始化

策略1:__temp object
以class X的copy constructor正确设置初值,然后再以biewise方式拷贝到局部实体,形式参数从原来的class X object转换为class X reference;class X声明一个destructor,

策略2: 拷贝构建
该位置视函数活动范围的不同记录于程序堆栈中

返回值初始化

1 加额外参数,类型是class object的一个reference
2 return指令前安插一个copy constructor

posted on 2025-02-24 13:57  Pomr  阅读(4)  评论(0)    收藏  举报