第一章、关于对象

1.关于对象
在C中,数据和处理数据的操作(函数)是分开的,也称程序方法为程序性的(procedural),在于它的精简。
在C++中是抽象数据类型(abstract data type,ADT),在于可复用和私密性。
加上封转后的成本并没有增加很多。对于数据成员class和struct一样,成员函数虽然在class的声明中,却不出现在object之中。
每个non-inline member function只会诞生一个函数实体,每一个拥有零个或一个定义的内联函数在每一个使用者身上产生一个函数实体。

/*小插曲:
内联函数在类中的优点是不用函数调用就能隐藏数据。
编译器遵循的第一个规则是无论发生什么事情,多态性必须起作用。也就是说当一个多态函数在类中定义时,即是多态和内联函数时,内联也不会展开,而是运行时多态。
内联函数和宏的区别:
1.内联函数在运行时可调试,而宏定义不可以;
2.编译器会对内联函数的参数类型做安全检查或自动类型转换(同普通函数),而宏定义则不会;
3.内联函数可以访问类的成员变量,宏定义则不能;
4.在类中声明同时定义的成员函数,自动转化为内联函数。
C++ 语言的函数内联机制既具备宏代码的效率,又增加了安全性,而且可以自由操作类的数据成员。
所以在C++ 程序中,应该用内联函数取代所有宏代码,“断言assert”恐怕是唯一的例外。
assert是仅在Debug版本起作用的宏,它用于检查“不应该”发生的情况。
为了不在程序的Debug版本和Release版本引起差别,assert不应该产生任何副作用。
如果assert是函数,由于函数调用会引起内存、代码的变动,那么将导致Debug版本与Release版本存在差异。
所以assert不是函数,而是宏。
具体实现:
void _assert(void *exp,void *file,unsigned int line)
{
    printf("Assert failed:%s , file %s, line %d\n",exp,file,line);
    abort();
}
#define assert(exp) (((void)(exp))||(_assert(#exp,__FILE__,__LINE__),0))
注意_assert返回的是viod,因此要用逗号来和0变成值为0
*/

C++在布局以及存取时间上主要的额外负担是由virtual引起,包括:虚函数机制和虚基类机制。

2.C++对象模型

c++中,有两种类数据成员:静态static和非静态nonstatic,以及三种类成员函数:静态、非静态和虚函数。

有三种数据模型:简单对象模型(每个指向函数的指针和变量都有一个slot)、表格驱动对象模型(两个指针指向两个表格:一个用来放成员变量,另外一个用来放函数地址)和
c++数据模型:非静态变量放在类对象内,静态变量、静态成员函数和非静态成员函数都放在所有的类对象之外。虚函数用两个步骤来支持:
1、每个类class产生一堆指向虚函数的指针,放在表格之中,这个表格被称为virtual table(vtbl)。
2、每一个类对象被添加一个指针virtual table,称为vptr,它的设定和重置都由一个class的构造函数(constructor)、析构函数(destructor)和拷贝构造函数(copy constructor)自动完成的。通常位于第一个slot处。

不是虚继承,有虚函数就把虚函数放在父类虚表中。是虚继承,自己产生一个虚指针指向虚表,每个虚继承的子类添加一个指向父类的指针。

单一继承的例子:
class Parent
{
public:
    int iparent;
    Parent():iparent(10){}
    virtual void f(){cout<<"Parent::f()"<<endl;}
    virtual void g(){cout<<"Parent::g()"<<endl;}
    virtual void h(){cout<<"Parent::h()"<<endl;}
};

class Child:public Parent
{
public:
    int ichild;
    Child():ichild(100){}
    void f(){cout<<"Child::f()"<<endl;}
    virtual void g_child() { cout << "Child::g_child()" << endl; }
    virtual void h_child() { cout << "Child::h_child()" << endl; }
};

class GrandChild:public Child
{
public:
    int iGrandChild;
    GrandChild():iGrandChild(1000){}
    virtual void f() { cout << "GrandChild::f()" << endl; }
    virtual void g_child() { cout << "GrandChild::g_child()" << endl; }
    virtual void h_grandchild() { cout << "GrandChild::h_grandchild()" << endl; }
};

typedef void(*func)(void);

int _tmain(int argc, _TCHAR* argv[])
{
    GrandChild gc;
    func pFun;
    int ** pvtr=(int **)&gc;
    cout << "[0] GrandChild::_vptr->" << endl;
    printf("[0] GrandChild::_vptr->\n");
    for(int i=0;(func)pvtr[0][i]!=NULL;i++)
    {
        pFun=(func)pvtr[0][i];
        cout<<"    ["<<i<<"] ";
        pFun();
    }
    //在gcc下有问题int* 转成 int 有问题。。
    cout << "[1] Parent.iparent = " << (int)pvtr[1] << endl;
    cout << "[2] Child.ichild = " << (int)pvtr[2] << endl;
    cout << "[3] GrandChild.igrandchild = " << (int)pvtr[3] << endl;
    return 0;
}

结果:
[0] GrandChild::_vptr->
[0] GrandChild::_vptr->
    [0] GrandChild::f()
    [1] Parent::g()
    [2] Parent::h()
    [3] GrandChild::g_child()
    [4] Child::h_child()
    [5] GrandChild::h_grandchild()
[1] Parent.iparent = 10
[2] Child.ichild = 100
[3] GrandChild.igrandchild = 1000

多重继承的例子:
class Base1 {
public:
    int ibase1;
    Base1():ibase1(10) {}
    virtual void f() { cout << "Base1::f()" << endl; }
    virtual void g() { cout << "Base1::g()" << endl; }
    virtual void h() { cout << "Base1::h()" << endl; }

};

class Base2 {
public:
    int ibase2;
    Base2():ibase2(20) {}
    virtual void f() { cout << "Base2::f()" << endl; }
    virtual void g() { cout << "Base2::g()" << endl; }
    virtual void h() { cout << "Base2::h()" << endl; }
};

class Base3 {
public:
    int ibase3;
    Base3():ibase3(30) {}
    virtual void f() { cout << "Base3::f()" << endl; }
    virtual void g() { cout << "Base3::g()" << endl; }
    virtual void h() { cout << "Base3::h()" << endl; }
};

class Derive : public Base1, public Base2, public Base3 {
public:
    int iderive;
    Derive():iderive(100) {}
    virtual void f() { cout << "Derive::f()" << endl; }
    virtual void g1() { cout << "Derive::g1()" << endl; }
};
typedef void(*Fun)(void);

int _tmain(int argc, _TCHAR* argv[])
{
    Derive d;

    int** pVtab = (int**)&d;

    cout << "[0] Base1::_vptr->" << endl;
    Fun pFun = (Fun)pVtab[0][0];
    cout << "     [0] ";
    pFun();

    pFun = (Fun)pVtab[0][1];
    cout << "     [1] ";pFun();

    pFun = (Fun)pVtab[0][2];
    cout << "     [2] ";pFun();

    pFun = (Fun)pVtab[0][3];
    cout << "     [3] "; pFun();

    pFun = (Fun)pVtab[0][4];
    cout << "     [4] "; cout<<pFun<<endl;

    cout << "[1] Base1.ibase1 = " << (int)pVtab[1] << endl;

    int s = sizeof(Base1)/4;

    cout << "[" << s << "] Base2::_vptr->"<<endl;
    pFun = (Fun)pVtab[s][0];
    cout << "     [0] "; pFun();

    pFun = (Fun)pVtab[s][1];
    cout << "     [1] "; pFun();

    pFun = (Fun)pVtab[s][2];
    cout << "     [2] "; pFun();

    pFun = (Fun)pVtab[s][3];
    cout << "     [3] ";
    cout<<pFun<<endl;

    cout << "["<< s+1 <<"] Base2.ibase2 = " << (int)pVtab[s+1] << endl;

    s = s + sizeof(Base2)/4;

    cout << "[" << s << "] Base3::_vptr->"<<endl;
    pFun = (Fun)pVtab[s][0];
    cout << "     [0] "; pFun();

    pFun = (Fun)pVtab[s][1];
    cout << "     [1] "; pFun();

    pFun = (Fun)pVtab[s][2];
    cout << "     [2] "; pFun();

    pFun = (Fun)pVtab[s][3];
    cout << "     [3] ";
    cout<<pFun<<endl;

    s++;
    cout << "["<< s <<"] Base3.ibase3 = " << (int)pVtab[s] << endl;
    s++;
    cout << "["<< s <<"] Derive.iderive = " << (int)pVtab[s] << endl;

    return 0;
}
结果为:
[0] Base1::_vptr->
     [0] Derive::f()
     [1] Base1::g()
     [2] Base1::h()
     [3] Derive::g1()
     [4] 00000000
[1] Base1.ibase1 = 10
[2] Base2::_vptr->
     [0] Derive::f()
     [1] Base2::g()
     [2] Base2::h()
     [3] 00000000
[3] Base2.ibase2 = 20
[4] Base3::_vptr->
     [0] Derive::f()
     [1] Base3::g()
     [2] Base3::h()
     [3] 00000000
[5] Base3.ibase3 = 30
[6] Derive.iderive = 100

重复继承,派生类的虚函数放在子类的虚表中,例子:
class B
{
    public:
        int ib;
        char cb;
    public:
        B():ib(0),cb('B') {}
        virtual void f() { cout << "B::f()" << endl;}
        virtual void Bf() { cout << "B::Bf()" << endl;}
};
class B1 :  public B
{
    public:
        int ib1;
        char cb1;
    public:
        B1():ib1(11),cb1('1') {}
        virtual void f() { cout << "B1::f()" << endl;}
        virtual void f1() { cout << "B1::f1()" << endl;}
        virtual void Bf1() { cout << "B1::Bf1()" << endl;}
};
class B2:  public B
{
    public:
        int ib2;
        char cb2;
    public:
        B2():ib2(12),cb2('2') {}
        virtual void f() { cout << "B2::f()" << endl;}
        virtual void f2() { cout << "B2::f2()" << endl;}
        virtual void Bf2() { cout << "B2::Bf2()" << endl;}
};
class D : public B1, public B2
{
    public:
        int id;
        char cd;
    public:
        D():id(100),cd('D') {}
        virtual void f() { cout << "D::f()" << endl;}
        virtual void f1() { cout << "D::f1()" << endl;}
        virtual void f2() { cout << "D::f2()" << endl;}
        virtual void Df() { cout << "D::Df()" << endl;}
};
int _tmain(int argc, _TCHAR* argv[])
{
    typedef void(*Fun)(void);
    int** pVtab = NULL;
    Fun pFun = NULL;
    D d;
    pVtab = (int**)&d;
    cout << "[0] D::B1::_vptr->" << endl;
    pFun = (Fun)pVtab[0][0];
    cout << "     [0] ";    pFun();
    pFun = (Fun)pVtab[0][1];
    cout << "     [1] ";    pFun();
    pFun = (Fun)pVtab[0][2];
    cout << "     [2] ";    pFun();
    pFun = (Fun)pVtab[0][3];
    cout << "     [3] ";    pFun();
    pFun = (Fun)pVtab[0][4];
    cout << "     [4] ";    pFun();
    pFun = (Fun)pVtab[0][5];
    cout << "     [5] 0x" << pFun << endl;
    cout << "[1] B::ib = " << (int)pVtab[1] << endl;
    cout << "[2] B::cb = " << (char)pVtab[2] << endl;
    cout << "[3] B1::ib1 = " << (int)pVtab[3] << endl;
    cout << "[4] B1::cb1 = " << (char)pVtab[4] << endl;
    cout << "[5] D::B2::_vptr->" << endl;
    pFun = (Fun)pVtab[5][0];
    cout << "     [0] ";    pFun();
    pFun = (Fun)pVtab[5][1];
    cout << "     [1] ";    pFun();
    pFun = (Fun)pVtab[5][2];
    cout << "     [2] ";    pFun();
    pFun = (Fun)pVtab[5][3];
    cout << "     [3] ";    pFun();
    pFun = (Fun)pVtab[5][4];
    cout << "     [4] 0x" << pFun << endl;
    cout << "[6] B::ib = " << (int)pVtab[6] << endl;
    cout << "[7] B::cb = " << (char)pVtab[7] << endl;  
    cout << "[8] B2::ib2 = " << (int)pVtab[8] << endl;
    cout << "[9] B2::cb2 = " << (char)pVtab[9] << endl;
    cout << "[10] D::id = " << (int)pVtab[10] << endl;
    cout << "[11] D::cd = " << (char)pVtab[11] << endl;
    return 0;
}
输出为:
[0] D::B1::_vptr->
     [0] D::f()
     [1] B::Bf()
     [2] D::f1()
     [3] B1::Bf1()
     [4] D::Df()
     [5] 0x00000000
[1] B::ib = 0
[2] B::cb = B
[3] B1::ib1 = 11
[4] B1::cb1 = 1
[5] D::B2::_vptr->
     [0] D::f()
     [1] B::Bf()
     [2] D::f2()
     [3] B2::Bf2()
     [4] 0x00000000
[6] B::ib = 0
[7] B::cb = B
[8] B2::ib2 = 12
[9] B2::cb2 = 2
[10] D::id = 100
[11] D::cd = D
我们可以看见,最顶端的父类B其成员变量存在于B1和B2中,并被D给继承下去了。
而在D中,其有B1和B2的实例,于是B的成员在D的实例中存在两份,一份是B1继承而来的,另一份是B2继承而来的。
所以,如果我们使用以下语句,则会产生二义性编译错误:
D d;
d.ib = 0;               //二义性错误
d.B1::ib = 1;           //正确
d.B2::ib = 2;           //正确

虚拟继承,在每个虚继承下都有一个指向虚父类的指针。例子:
class B
{
    public:
        int ib;//4个字节
        char cb;//4个字节
    public:
        B():ib(0),cb('B') {}
        //4个字节的虚指针
        virtual void f() { cout << "B::f()" << endl;}
        virtual void Bf() { cout << "B::Bf()" << endl;}
};
class B1 : virtual public B
{
    public:
        int ib1;//4个字节
        char cb1;//4个字节
    public:
        B1():ib1(11),cb1('1') {}
        //4个字节的虚指针
        virtual void f() { cout << "B1::f()" << endl;}
        virtual void f1() { cout << "B1::f1()" << endl;}
        virtual void Bf1() { cout << "B1::Bf1()" << endl;}
        //4个字节指向B
        //在VS2012下多了一个值为0的4个字节整数
        //B的12个字节
};
class B2: virtual public B
{
    public:
        int ib2;
        char cb2;
    public:
        B2():ib2(12),cb2('2') {}
        virtual void f() { cout << "B2::f()" << endl;}
        virtual void f2() { cout << "B2::f2()" << endl;}
        virtual void Bf2() { cout << "B2::Bf2()" << endl;}
};
class D : public B1, public B2
{
    public:
        int id;
        char cd;
    public:
        D():id(100),cd('D') {}
        virtual void f() { cout << "D::f()" << endl;}
        virtual void f1() { cout << "D::f1()" << endl;}
        virtual void f2() { cout << "D::f2()" << endl;}
        virtual void Df() { cout << "D::Df()" << endl;}
};
int _tmain(int argc, _TCHAR* argv[])
{
    typedef void(*Fun)(void);
    int** pVtab = NULL;
    Fun pFun = NULL;
    cout<<sizeof(B)<<endl;
    cout<<sizeof(B1)<<endl;
    cout<<sizeof(B2)<<endl;
    cout<<sizeof(D)<<endl;
    D d,dd;
    B1 bb1;
    pVtab = (int**)&bb1;
    cout << "[0] B1::_vptr->" << endl;
    pFun = (Fun)pVtab[0][0];
    cout << "     [0] ";
    pFun(); //B1::f1();
    cout << "     [1] ";
    pFun = (Fun)pVtab[0][1];
    pFun(); //B1::bf1();
    cout << "     [2] ";
    cout << pVtab[0][2] << endl;
    cout << "[1] = 0x";
    cout << (int*)*((int*)(&bb1)+1) <<endl; //B1::ib1
    cout << "[2] B1::ib1 = ";
    cout << (int)*((int*)(&bb1)+2) <<endl; //B1::ib1
    cout << "[3] B1::cb1 = ";
    cout << (char)*((int*)(&bb1)+3) << endl; //B1::cb1
    cout << "[4] = 0x";
    cout << (int*)*((int*)(&bb1)+4) << endl; //NULL
    cout << "[5] B::_vptr->" << endl;
    pFun = (Fun)pVtab[5][0];
    cout << "     [0] ";
    //pFun(); //B1::f();
    pFun = (Fun)pVtab[5][1];
    cout << "     [1] ";
    pFun(); //B::Bf();
    cout << "     [2] ";
    cout << "0x" << (Fun)pVtab[5][2] << endl;
    cout << "[6] B::ib = ";
    cout << (int)*((int*)(&bb1)+6) <<endl; //B::ib
    cout << "[7] B::cb = "<<(int)*((int*)(&bb1)+7) <<endl;

     pVtab = (int**)&d;
    cout << "[0] D::B1::_vptr->" << endl;
    pFun = (Fun)pVtab[0][0];
    cout << "     [0] ";    pFun(); //D::f1();
    pFun = (Fun)pVtab[0][1];
    cout << "     [1] ";    pFun(); //B1::Bf1();
    pFun = (Fun)pVtab[0][2];
    cout << "     [2] ";    pFun(); //D::Df();
    pFun = (Fun)pVtab[0][3];
    cout << "     [3] ";
    cout << pFun << endl;
    //cout << pVtab[4][2] << endl;
    cout << "[1] = 0x";
    cout << (int)*(int*)((&dd)+1) <<endl; //????
    cout << "[2] B1::ib1 = ";
    cout << *((int*)(&dd)+2) <<endl; //B1::ib1
    cout << "[3] B1::cb1 = ";
    cout << (char)*((int*)(&dd)+3) << endl; //B1::cb1
    //---------------------
    cout << "[4] D::B2::_vptr->" << endl;
    pFun = (Fun)pVtab[4][0];
    cout << "     [0] ";    pFun(); //D::f2();
    pFun = (Fun)pVtab[4][1];
    cout << "     [1] ";    pFun(); //B2::Bf2();
    pFun = (Fun)pVtab[4][2];
    cout << "     [2] ";
    cout << pFun << endl;
    cout << "[5] = 0x";
    cout << (int)*((int*)(&dd)+5) << endl; // ???
    cout << "[6] B2::ib2 = ";
    cout << (int)*((int*)(&dd)+6) <<endl; //B2::ib2
    cout << "[7] B2::cb2 = ";
    cout << (char)*((int*)(&dd)+7) << endl; //B2::cb2
    cout << "[8] D::id = ";
    cout << *((int*)(&dd)+8) << endl; //D::id
    cout << "[9] D::cd = ";
    cout << (char)*((int*)(&dd)+9) << endl;//D::cd
    cout << "[10]  = 0x";
    cout << (int*)*((int*)(&dd)+10) << endl;
    //---------------------
    cout << "[11] D::B::_vptr->" << endl;
    pFun = (Fun)pVtab[11][0];
    cout << "     [0] ";   
    //pFun(); //D::f();
    pFun = (Fun)pVtab[11][1];
    cout << "     [1] ";    pFun(); //B::Bf();
    pFun = (Fun)pVtab[11][2];
    cout << "     [2] ";
    cout << pFun << endl;
    cout << "[12] B::ib = ";
    cout << *((int*)(&dd)+12) << endl; //B::ib
    cout << "[13] B::cb = ";
    cout << (char)*((int*)(&dd)+13) <<endl;//B::cb
    return 0;
}

输出:
12
32//至于大小为什么是32而不是28,应该和编译器有关,在VS2012中在虚基类之前添加4个字节的0整数
32//至于大小为什么是32而不是28,应该和编译器有关,在VS2012中在虚基类之前添加4个字节的0整数
56//至于大小为什么是56而不是52,应该和编译器有关,在VS2012中在虚基类之前添加4个字节的0整数
[0] B1::_vptr->
     [0] B1::f1()
     [1] B1::Bf1()
     [2] 976892226
[1] = 0x00371BC4
[2] B1::ib1 = 11
[3] B1::cb1 = 1
[4] = 0x00000000
[5] B::_vptr->
     [0]      [1] B::Bf()
     [2] 0x00000000
[6] B::ib = 0
[7] B::cb = -858993598
//下面是D的内存分布
[0] D::B1::_vptr->
     [0] D::f1()
     [1] B1::Bf1()
     [2] D::Df()
     [3] 00373650
[1] = 0x-858993460
[2] B1::ib1 = 11
[3] B1::cb1 = 1
[4] D::B2::_vptr->
     [0] D::f2()
     [1] B2::Bf2()
     [2] 00373664
[5] = 0x3612228
[6] B2::ib2 = 12
[7] B2::cb2 = 2
[8] D::id = 100
[9] D::cd = D
[10]  = 0x00000000
[11] D::B::_vptr->
     [0]      [1] B::Bf()
     [2] 663A3A44
[12] B::ib = 0
[13] B::cb = B

虚继承的缺点是由于间接性而导致空间和存取时间上的额外负担,优点是:由于基类在最后,所以每个类对象中对于继承都有一致的表现方式。
每一个类对象都应该在某个固定位置上安放一个基类指针,和基类大小或数目无关。第二个有点是不需要改变类对象本身就可以放大、缩小、或更改基类表
http://haoel.blog.51cto.com/313033/124561

/*
虚函数和纯虚函数的区别:
虚函数体现了oop中的继承和多态两大特性,即可以直接使用又可以被子类重载后调用。
纯虚函数只是一个接口,是个函数的声明而已,virtual  { } = 0;不能实例化含有纯虚函数的类,并且纯虚函数必须要在子类中实现。
相同点:虚函数和纯虚函数的定义中不能有static标识符,因为他们都要动态绑定,而staic是前期绑定
*/

3.对象模型影响程序
不同的对象模型会导致现有的程序代码修改和添加新的程序代码。

例子:
class X
{
public:
    virtual ~X();
    virtual void foo();
};
void X::foo()
{
    cout<<"X::foo()"<<endl;
}
X foobar()
{
    X xx;
    X *px=new X;
    xx.foo();
    px->foo();
    delete px;
    return xx;
}

内部函数foobar()可能修改如下:
void foobar(X &_result)
{
    //构造_result来取代局部变量
    _result.X::X();
    //扩展X *px=new X;
    px=_new(sizeof(X));
    if(px!=0)
        px->X::X();
    //扩展xx.foo()但不使用virtual机制,注意有个this的默认改写
    foo(&_result);
    //使用virtual机制扩展,但是书里面是px->vbtl[2],其实看编译器,一般第一个没有类的信息槽,所以不是2。
    (*px->vbtl[1])(px);
    //扩展delete px
    if(px!=0)
    {
        (*px->vtbl[0])(px);
        _delete(px);
    }
    //不需要使用named return statement
    //不需要摧毁local object xx
    return;
}

4.关键词带来的差异
为了和c兼容付出的代价:
如果没有需要八种整数需要支持,overload function的解决方式将会简单多。
如果丢掉C的声明语句,就不需要花时间判断是调用还是声明:
int (*pf)(1024);//看到1024是才知道是调用
int (*pq)();//无法区别是一个声明还是表达式用来调用哪个是,最基本的规则是将其看作是声明。
strct关键字是实现了C的数据萃取的观念,而class关键字是实现C++的ADT(abstract data type)观念。
/*
struct和class的区别:
1、最本质的一个区别就是默认的访问控制(无论是继承还是类里面):
struct作为数据结构的实现体,它默认的数据访问控制是public的,而class作为对象的实现体,它默认的成员变量访问控制是private的。
2、class可以做模板的关键字,而struct不行。
其他的没区别:即使struct可以
struct A //定义一个struct
{
   char c1;
   int n2;
   double db3;
};
A a={'p', 7, 3.1415926}; //定义时直接赋值
class加上public也行。
*/

5.对象的差异
C++支持三种程序设计典范(programming paradingms)
程序模型(也就是过程)、抽象数据模型(所谓的抽象是和一组表达式public接口一起提供)、面向对象模型

只有通过指针和引用才能支持面向对象所需的多态性质,原则上指针和引用只有在一个特定执行点才可以解析(说白了就是赋值)
注意还要求是类,如果是基本类型如int *a;void *b;则没有多态可言

假设有以下关系
Library_material
        |
    Book(子类)
//描述objects:不确定类型
Library_material *px= getsome();
Library_material &rx=*px;
//描述已知物,一定是Library_material
Library_material dx=*px;

一个类对象需要要多少内存:1、非静态成员函数的总和,2、可能的填充,3、为了支持virtual机制而产生的负担。
一个指针的大小永远是一个int的大小,引用的话就看引用的对象。

转型只是一种编译器指令,大部分情况下它并不改变一个指针所含的真正地址,它只影响被指出的内存的大小和其内容的解释方式。

/*
C++的四大转型:
const_cast<type_id> (expression) 用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。
reinterpret_cast<type-id> (expression)实际动作及结果可能取决于编译器,这也就表示它不可移植。type-id 必须是一个指针、引用、算术类型、函数指针或者成员指针。是为了映射到一个完全不同类型的意思,很危险。
static_cast运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它和reinterpret_cast<type-id>的区别就在于多重继承,不能转换掉expression的const、volatile、或者__unaligned属性。
dynamic_cast < type-id > ( expression )把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void*;在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;
在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。如果downcast是安全的(也就说,如果基类指针或者引用确实指向一个派生类对象)这个运算符会传回适当转型过的指针。如果downcast不安全,这个运算符会传回空指针(也就是说,基类指针或者引用没有指向一个派生类对象)。对于引用则会异常。
dynamic_cast可以支持交叉转换。
const_cast<type_id> (expression) 用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。
    一、常量指针被转化成非常量指针,并且仍然指向原来的对象;
  二、常量引用被转换成非常量引用,并且仍然指向原来的对象;
  三、常量对象被转换成非常量对象,是不同的对象。 
  type_id 必须为指针或引用


class B
{
public:
    int m_iNum;
    B():m_iNum(50) {}
};

void foo()
{
    //一定要新建一个
    const B *b1 = new B();
    //b1->m_iNum = 100; //compile error
    B *b2 = const_cast<B*>(b1);
    b2->m_iNum = 200;
    cout<<"b1: "<< b1->m_iNum <<endl;
    cout<<"b2: "<< b2->m_iNum <<endl;
    cout<<endl;
    const B b3;
    //b3.m_iNum = 100; //compile error
    B b4 = const_cast<B&>(b3);//b4 is another object
    b4.m_iNum = 200;
    cout<<"b3: "<<b3.m_iNum <<endl;
    cout<<"b4: "<<b4.m_iNum <<endl;
    cout<<endl;
    const B b5;
    //b5.m_iNum = 100; //compile error
    B &b6 = const_cast<B&>(b5);
    b6.m_iNum = 200;
    cout<<"b5: "<<b5.m_iNum <<endl;
    cout<<"b6: "<<b6.m_iNum <<endl;
    cout << endl;
    // force to convert
    const int x = 50;
    int* y = (int *)(&x);// same address, but the content is different
    *y = 200;
    cout << "x: "<<x<<" address: "<<&x<<endl;
    cout << "*y: "<<*y<<" address: "<<y<<endl;
    cout<<endl;
    // int
    const int xx = 50;
    int* yy = const_cast<int *> (&xx);// same address, but the content is different
    *yy = 200;
    cout << "xx: "<<xx<<" address: "<<&xx<<endl;
    cout << "*yy: "<<*yy<<" address: "<<yy<<endl;
    cout<<endl;
    // int
    const int xxx = 50;
    int yyy = const_cast<int&> (xxx);// another int
    yyy = 200;
    cout << "xxx: "<<xxx<<" address: "<<&xxx<<endl;
    cout << "yyy: "<<yyy<<" address: "<<&yyy<<endl;
}

int _tmain(int argc, char* argv[])
{
    foo();
    return 0;
}
  输出为:
b1: 200
b2: 200

b3: 100
b4: 200

b5: 200
b6: 200

x: 50 address: 0030F784
*y: 200 address: 0030F784

xx: 50 address: 0030F76C
*yy: 200 address: 0030F76C

xxx: 50 address: 0030F754
yyy: 200 address: 0030F748
reinterpret_cast<type-id> (expression)实际动作及结果可能取决于编译器,这也就表示它不可移植。
type-id 必须是一个指针、引用、算术类型、函数指针或者成员指针。
它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值)
reinterpret_cast是为了映射到一个完全不同类型的意思,这个关键词在我们需要把类型映射回原有类型时用到它。我们映射到的类型仅仅是为了故弄玄虚和其他目的,这是所有映射中最危险的。
static_cast和reinterpret_cast的区别主要在于多重继承
class A {
    public:
    int m_a;
};
class B {
    public:
    int m_b;
};
class C : public A, public B {};
C c;
printf("%p, %p, %p", &c, reinterpret_cast<B*>(&c), static_cast <B*>(&c));
前两个的输出值是相同的,最后一个则会在原基础上偏移4个字节,这是因为static_cast计算了父子类指针转换的偏移量,并将之转换到正确的地址(c里面有m_a,m_b,转换为B*指针后指到m_b处),而reinterpret_cast却不会做这一层转换。

static_cast运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:
①用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。
进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;
进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
③把空指针转换成目标类型的空指针。
④把任何类型的表达式转换成void类型。
注意:static_cast不能转换掉expression的const、volatile、或者__unaligned属性。
C++中的reinterpret_cast主要是将数据从一种类型的转换为另一种类型。所谓“通常为操作数的位模式提供较低层的重新解释”也就是说将数据以二进制存在形式的重新解释。

dynamic_cast < type-id > ( expression )
该运算符把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void*;
如果type-id是类指针类型,那么expression也必须是一个指针,如果type-id是一个引用,那么expression也必须是一个引用。
dynamic_cast运算符可以在执行期决定真正的类型。如果downcast是安全的(也就说,如果基类指针或者引用确实指向一个派生类对象)这个运算符会传回适当转型过的指针。如果downcast不安全,这个运算符会传回空指针(也就是说,基类指针或者引用没有指向一个派生类对象)。
dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。
在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;
在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
dynamic_cast可以支持交叉转换。
*/

假设有以下关系
class Bear:public ZooAnimal{
public:
Bear();
~Bear();
protected:
int cell_block;
};
Bear b;
ZooAnimal *pz=&b;
Bear *pb=&b;
//不合法:cell_block不是ZooAnimal的一个成员
pz->cell_block;
//经过转型就可以
((Bear *)pz)->cell_block;
//下面更好
if(Bear *pb2=dynamic_cast<Bear*>(pz))
pb2->cell_block;
//没问题,cell_block本身是pb的成员
pb->cell_block;

一个point或一个reference之所以支持多态,是因为他们并不引发内存中任何”与类型有关的内存委托操作(type-dependent commitment)“;会受改变的是它们所指向的内存的大小和内容解释方式而已。

posted @ 2014-05-14 12:58  Tempal  阅读(255)  评论(0编辑  收藏  举报