数据成员直接放在每一个类对象之中. 而成员函数虽在class的声明之内, 却不出现在对象之中. 每一个非内联成员函数值会诞生一个函数实例. 至于每一个"拥有零个或一个定义"的内联函数则会在其每一个使用者(模块)身上产生一个函数实例
C++中, 有两种数据成员: static和nonstatic, 以及三种类成员函数: static, nonstatic和virtual.
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;
};
简单对象模型: 成员本身并不放在对象之中. 只有"指向成员的指针"才放在object内. 这么做可以避免"members有不同的类型, 因而需要不同的存储空间"所招致的问题. 它可能是为了尽量减低C++编译器的设计复杂度而开发出来的, 赔上的则是空间和执行期的效率.
表格驱动对象模型: 为对所有类的对象都有一致的表达方式, 把所有与成员相关的信息抽取出来, 放在一个data member table和一个member functio table指针, 类对象本身则内含指向这两个表格的指针.
C++ 对象模型: 非静态数据成员被配置于每一个类对象之内, 静态数据成员则被存放在个别的类对象之外. 静态和非静态函数成员也被存放在个别的类对象之外, 虚函数则以两个步骤支持之:
加上继承: C++支持单一继承, 多继承和虚继承(在虚拟继承的情况下, 基类不管在继承串链中被派生多少次, 永远只会存在一个实例, 例如iostream之中就只有virtual ios基类的一个实例)
派生类模塑其基类实例:
对象模型如何影响程序
不同的对象模型, 会导致"现有的程序代码必须修改"以及"必须加入新的程序代码"连个结果
X foobar() {
X xx;
X *px = new X;
// foo()是一个virtual function
xx.foo();
px->foo();
delete px;
return xx;
};
这个函数有可能在内部被转化为
X foobar() {
X xx;
X *px = new X;
// foo()是一个virtual function
xx.foo();
px->foo();
delete px;
return xx;
};
关键词困惑
两个node重定义
class node {};
struct node {};
报错
template<struct Type>
struct number {};
不报错
template<class Type>
struct numble {};
策略性正确的struct
待补充
C++程序设计模型直接支持三种程序设计规范(programming paradigms): 1. 程序模型; 2. 抽象数据类型模型; 3. 面向对象模型
虽然可以直接或简介处理继承体系中的一个基类对象, 但只有通过指针或引用的间接处理, 才支持OO程序设计所需的多态性质
thing1的定义和运用逸出了OO的习惯, 它反应的是ADT paradigm的行为
Library_materials thing1;
// class Book : public Library_materials { ... };
Book book;
// thing1不是一个Book!
// book被裁减
// 不过thing1仍保有一个Library_materials
thing1 = book;
// 调用的是Library_maternal::check_in()
thing1.check_in();
thing2的定义和语言, 是OO paradigm中的一个良好例证
// OK: 现在thing2参考到book
Library_maternal &thing2 = book;
// OK 现在引发的是Book::check_in()
thing2.check_in();
在OO paradigm之中, 程序员需要处理一个位置实例, 它的类型虽然有所界定, 却有无穷可能. 这组类型受限于其继承体系, 然而该体系理论上没有深度和广度的限制. 在C++中, 只有通过指针和引用的操作来完成. 相反, 在ADT paradigm中, 程序员处理的是一个拥有固定而单一类型的实例, 它在编译期间就已经完全定义好了
// 描述objects: 不确定类型
Librar_maternal *px = retrieve_some_maternal();
Librar_maternal &rx = *px;
// 描述已知物: 不可能有令人惊讶的结果产生
Librar_maternal dx = *px
没有办法确定地说出px或tx到底指向何种类型对象, 只能确定要么是一个Librar_maternal类型要么就是Librar_maternal的子类型. dx可以确定是Librar_maternal类的一个对象
C++中指针或引用的处理不是多态的必要结果
// 没有多态, 因为操作对象不是class object
int *pi;
// 没有语言所支持的多态, 因为操作对象不是class object
void *pvi;
// ok: class x视为一个基类, 可以有多态效果
x *px;
一般而言类对象所需内存要有
指针的类型
指针的大小都是一样的, 都是存储指向对象的地址, 区别仅仅是"指针类型", 他会知道编译器如何解释某个特定地址中的内存内容及大小, 即影响解释方式
class ZooAnimal {
public:
ZooAnimal();
virtual ~ZooAnimal();
// ...
virtual void rotate();
protected:
int loc;
string name;
};
ZooAnimal za("Zoey");
ZooAnimal *pza = &za;
class Bear : public ZooAnimal {
public:
Bear();
~Bear();
// ...
void rotate();
virtual void dance();
// ...
protected:
enum Dances {...};
Dance dances_know;
int cell_block;
};
Bear b("Yogi");
Bear *pb = &b;
Bear &rb = *pb;
她们每个都指向Bear对象的第一个byte. 期间的差别是, pb所涵盖的地址包含整个Bear对象, 而pz所涵盖的地址只包含Bear对象中的ZooAnimal, 除了ZooAnimal中出现的成员, 不能使用pz来直接处理Bear的任何成员, 可通过转换pz的类型间接实现. 唯一例外的是通过virtual机制
Bear b;
ZooAnimal za = b; // 会引起切割
// 调用ZooAnimal::rotate()
za.rotate();
这里会引起两个问题: 1.为什么rotate()所调用的是ZooAnimal实例而不是Bear实例? 2.如果初始化函数讲一个对象内容完整拷贝到另一个对象去, 为什么za的vptr不指向Bear的virtual table
原文:https://www.cnblogs.com/hesper/p/10588654.html