深入探索C++对象模型读书笔记 (一)

Posted on 2010-03-03 13:58 rikisand 阅读(1976) 评论(0)  编辑 收藏 引用 所属分类: C/C++

寒假基本读了一遍,现在再读一遍,做下笔记。

笔记当做的精炼而有意义,而后回顾可知其意,回其味,方有成效

---------------------------------------------------------------------------------

C语言:数据和操纵数据的方法分开声明,方法被写成函数处理外部数据

C++:数据和方法的组合封装ADT 更安全 支持继承 清晰

封装在空间上的代价:

如果仅仅是普通继承则并没有什么代价,因为每个数据成员直接内涵在每一个class对象中,和c中的struct一样,而member function如果不是inline的则只会产生一个实体,而inline会在每一个使用的模块产生一个函数实体

c++在空间和存取效率的代价主要由virtual带来:

virtual function 机制: vtable vptr 执行期绑定

virtual class 机制:

还有多重继承下的额外负担(子类转换成第二个父类的时候)

----------------------------------------------------------------------

c++对象模型:也就是我们怎么在内存中安排各个数据成员以及成员函数

1.简单对象模型~ 对象由各个slot组成,每一个slot包含指针,指向各个成员

2.表格驱动模型~ 对象含有两个指针,一个指向成员数据表,另一个指向成员函数表

3.c++实际对象模型~ 非静态数据被放在对象内,而静态数据成员放在对象外(显然啊,他属于类),成员函数

  不管静态或者非静态都放在对象外面

  Virtual functions :每个class产生一堆指向vitrualfunctions的指针,放在vtables中,每个对象

  含有vptr 指向vtable vptr的设定,重置均有class的ctor,dtor,copy assignment 运算符自动完成

  优点:空间和存储效率 缺点:如果对象模型的nonstatic data members 有所修改,也就是对象内部布局有所更改,那么使用该对象的应用程序需要重新编译.

虚拟继承:不管基类被派生了多少次,永远只有一个实体(菱形继承最下面对象中只有一个顶部类实体)

继承的实现:一种可以用basetable 在basetable中指向一个baseclass的地址,但这会随着继承深度越来越深变得慢

现在采用的方法之后记录~~~ :P

书中的程序:对象模型对程序的影响:

X foobar(){
    X xx;
    X *px = new X;
    xx.foo();
    px->foo(); //foo是一个virtual function
    delete px;
    return xx;
}
//调用处 X _result;
//      foobar(_result);
void foobar(X& _result){
    _result.X::X();//构造result
    px = _new(sizeof(X));
    if(px!=0)
        px->X::X;
    foo(&_result);//使用result取代xx但是不激活virtual机制
    (*px->vtbl[2])(px);//使用virtual机制扩展px->foo();
    if(px!=0){
        (*px->vtbl[1])(px);//使用virtual调用destructor
        delete px;
    }
    //不用使用named return statement
    return ;
}

------------------------------------------------------------------------------------

关键词带来的麻烦~~

struct 和 class 在C++中可以混用,并不是由于使用哪一个决定其特性,只是给人的感觉不同罢了class更像是c++中继承的代名词 struct更像C中的数据集

如果需要向C函数传递数据集合可以使用struct以保证对象模型的支持

使用struct完全可以声明各种class的特性

对象的差异

1.程序模型procedural model  同c一样

2.抽象数据类型模型 ADT object-base 抽象指的是一族表达式(public接口)的提供,具体计算方法未明

3.面向对象 oo 有一些彼此相关的模型通过一个抽象的baseclass用以提供公共接口封装起来

 

OO中程序员可能需要处理一个未知实体,在执行点之前无法确定,这是由pointers和reference实现的而在ADT中程序员处理的是一个拥有固定单一类型的实体,编译时期就已经确定了~

c++中的多态:1.把derived class的指针转化成一个基类的指针 2virtualfunctions 3.dynamic_cast 和typeid运算符

多态主要是经由一个共同的接口来影响类型的封装,这个接口通常被放置在抽象的baseclass中,这个共享接口是以virtual functions机制来引发的,可以在执行期间根据object的真正类型解析出到底是哪一个函数实体被调用。

我们的代码可以避免由于增加某一个特定的derived 实体而改变,只需要新的derivedclass重写这样的接口便可。

//测试指针引用的多态
#include <iostream>
    using namespace std;
    struct Point{
    public:
        Point(float x=0.):_x(x){}
        float x(){return _x;}
        void x(float xval){_x=xval;}
        virtual void  out(){
            cout<<"I am a Point"<<endl;
        }
    protected:
        float _x;
    };
    struct Point2d:public Point{
    public:
        Point2d(float x=0.,float y=0.):Point(x),_y(y){}
        float y(){return _y;}
        void y(float yval){_y=yval;}
        virtual void out(){
            cout<<"I am a Point2d"<<endl;
        }
    protected:
        float _y;
    };
    int main(){
        Point pt;
        Point2d pt2;
        Point* ptr;
        Point2d* ptr2;
        pt.out(); pt2.out();
        pt=pt2;pt.out();
        ptr=&pt2;
        ptr->out();
        (*ptr).out();
        Point& ptref=pt2;
        ptref.out();
    }

output:

I am a Point
I am a Point2d
I am a Point
I am a Point2d
I am a Point2d
I am a Point2d

指针和引用可以实现多态,因为指针和引用的赋值只是改变其指向的范围,并没有触及对象模型的改变,因此可以产生多态的效果。而value的赋值操作会导致对象模型的切割,从而真实的改变了对象的内部模型与类型,失去了多态的效果。oo 不支持对对象的直接处理

 

指针的类型:

不同的指针从内存角度来看没什么不同,只是占据了一个word的空间,但是指针的类型会告诉编译器如何解释某个特定地址中的内存内容以及大小

 

OB设计也就是ADT设计比OO设置更有效率因为其所有函数引发操作均在编译器确定OO需要一些运行时确定,对象构建起来不需要设置virtual机制

比OO紧凑因为无需支持virtual机制从而没有额外负担

但是OB相对来说弹性较小~~