C++对象模型读书笔记

加上封装后的布局成本 layout cost:C的struct 到 C++的class

  • data members内含在class object内,和struct一样。
  • member functions含在class声明内,但是不出现在object中。
  • non-inline member function只会诞生一个函数实例
  • 每一个“拥有零个或一个定义”的inline function会在没一个使用者(模块)身上产生一个函数实例

总结:C++在布局以及存取时间上主要的额外负担是virtual引起的,包括:

  • virtual function机制:用以支持一个有效率的“执行期绑定”(runtime binding)
  • virtual base class:用以实现“多次出现在继承体系中的base class,有一个单一而被共享的实例”

30、struct和class

什么时候应该/可以将C++程序中的class用struct取代?

  • struct关键词其实没什么用
  • 可以使用struct取代class,但仍然声明public、protected、private等存取区段 与 完全public的接口,以及virtual functions和继承(单一、多重、虚拟)
  • struct是一个数据集合体,没有private data,也没有data的操作(member function)。
  • 问题:类型层次结构的原始声明中,根节点(root node)和每一个派生下来的子类型(subtype)用struct声明的。但陆续修改的头文件中,某些派生子类型(derived subtypes)的前置声明(forward declaration)却用class。
    • class node; struct node { … };
    • 不合法?不,只是不一致
  • struct实现了C中数据抽象观念,class实现了C++的抽象数据类型ADT观念。
  • C++要支持现存的C代码,它就不能不支持struct。C++引入class不仅仅是关键词,而是其所支持的封装和继承的哲学。

31、new和strlen

char *pstr;
pstr = new char[10];
std::cout << strlen(pstr) <<std::endl

这里输出不一定是10。pstr指向的内容没有初始化,已经越界访问了

char boy[] = "Danny";
char *p_son;
p_son = new char[strlen(boy) + 1];
strcpy(p_son, boy);

此外,strlen分配内存是比如 +1。一个字符串的结束标志是’\0’,你不+1能得到相同的字符串,但是这样是很危险的,随时有可能在后面的其他操作中带来巨大的错误!

32、基类和子类

1、通过 基类实例 完成多态。   ADT(抽象数据类型)范式的行为
Library thing1;
// class Book : public Library { ... };  子类实例
Book book;
// book被裁切(slided)了。不过thing1仍保留一个Library
thing1 = book;
// 调用的是 Library::func()
thing1.func();

2、通过 pointer 或 reference 完成多态。  OO程序设计的多态性质
Library &thing2 = book;
// 调用 Book::func()
thing2.func();

面向对象范式中,被指定的object的真实类型在每一个特定执行点之前是无法解析的。

C++中,只有通过 pointer 或 reference 的操作才能完成。

相反,ADT中处理的是一个拥有固定而单一类型的实例,在编译时期就已经完全定义好了。

// 无法确定px和rx指向何种类型的object,可能是Library object,也可能是后者的子类型(subtype)
Library *px = retrieve_library();
Library &rx = *px;

// 描述已知物。只能是Library object
Library dx = *px;

注意:

C++中,多态只存在于public class体系中。

Nonpublic的派生行为 和 类型为void*的指针 并没有被语言明确支持。他们必须由程序员显示的转换操作来管理。

int *pi;  // 不是多态,操作对象不是class obj
void *pvo;  // 不是多态,操作对象不是class obj
x *px; // 多态,class x视作一个base class

33、C++多态方法

1、经由隐式转换
shape *ps = new circle();
2、经由 virtual function 机制
ps -> rotate();
3、经由 dynamic_cast 和 typeid 运算符
if ( circle *pc = dynamic_cast<circle*>(ps) ) ...

​ C++多态的主要用途。经由一个共同的接口来影响类型的封装,这个接口通常被定义在抽象的base class中。

​ 这个共享接口是以virtual function机制引发的,可以在执行期间根据obj的真正类型解析出哪个函数实例被调用。

​ 意义:

  • 当类型有所增加、修改、删减时,程序代码无须改变。

  • 新的子类型不需要重新写出 “对继承体系中的所有类型都通用” 的行为和操作。

34、一个class object的内存大小

1:nonstatic data member的总和大小

2:alignment所填补的空间,可能存在于members之间,也可能是类的边界

3:为了支持virtual而由内部产生的额外负担,比如:指虚基类表的指针或指向虚函数表的指针

其中1和3都比较好确定,比较难确定的是2中的内存对齐(填补)的大小

35、不同类型的指针有什么不同?怎么区分?

Library *px;
int *pi;
Array<String> *pta;

指针存储的都是一个“机器地址”,通常是个word,其大小不一定,可能是16-bits。

上述指针的差异,不在于指针表示法不同,不在于内容(都表示一个地址)不同,而在于其所寻址出来的object类型不同。

“指针类型”会指导编译器解释某个特定地址的内存内容和其大小。

void *的指针只能持有一个地址,不能通过它操作所指向的object。不知道其涵盖的地址空间。

转换(cast)实际上是一种编译器指令。大部分情况下不改变指针所含的地址,而影响“被指向之内存的大小和其内容”的解释方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值