• C++ 对象模型学习记录(2) 第3章 data语义学


    1. 关于sizeof的运行结果

    #include <iostream>
    //在GCC 中
    using namespace std;
    class X{};
    class Y :public X{};
    class Z : public X{};
    class W :public Y,public Z{};
    int main()
    {
    cout
    << sizeof(X) << endl;//1
    cout
    << sizeof(Y) << endl;//1
    cout
    << sizeof(Z) << endl;//1
    cout
    << sizeof(W) << endl;//2
    return 0;
    }

      而在vs 2010中是默认的编译器中

    #include <iostream>

    using namespace std;
    class X{};
    class Y :public X{};
    class Z : public X{};
    class W :public Y,public Z{};
    int main()
    {
    cout
    << sizeof(X) << endl;//1
    cout << sizeof(Y) << endl;//1
    cout << sizeof(Z) << endl;//1
    cout << sizeof(W) << endl;//1
    return 0;
    }

      加了虚继承后,GCC和vs的竟然相同了,总的来说就是有了 virtual 继承,加了一个vptr指针和指向的是一个 要么是virtual base table,要么是offset

    #include <iostream>

    using namespace std;
    class X{};
    class Y :public virtual X{};
    class Z : public virtual X{};
    class W :public Y,public Z{};
    int main()
    {
    cout
    << sizeof(X) << endl;//1
    cout << sizeof(Y) << endl;;//4
    cout << sizeof(Z) << endl;//4
    cout << sizeof(W) << endl;//8
    return 0;
    }

     2. 关于指向data member 数据成员的指针

    #include <iostream>
    #include
    <stdio.h>
    using namespace std;
    struct Base1{int val1; };
    struct Base2{int val2; };
    struct Derived : Base1,Base2 {};
    //Derived2为了和Derived比较
    struct Derived2 : Base1,Base2{int val3;};
    void func1(int Derived::*dmp,Derived *pd)
    {
    //期望传进来的是一个"指向 derived class 的member "的指针
    //如果传进来的是“指向base class 的member”的指针,
    //结果如何?
    cout << pd->*dmp << endl;
    }
    void func2(Derived *pd)
    {
    //bmp将成为1
    int Base2::* bmp = &Base2::val2;//Base2::* 型的变量
    cout << bmp << endl;
    printf(
    "~~~~~~~~~~~~~~~~~~~%d\n",bmp);

    func1(bmp,pd);
    //这里必须由编译器内部转换
    // func1(,pd);
    }
    int main()
    {
    Base1 base1;
    base1.val1
    = 1;
    Base2 base2;
    base2.val2
    = 2;
    Derived d;
    Derived
    *p = &d;
    func2(p);
    cout
    << "-------------------" << endl;
    //以下结果都是0
    printf("&Base1::val1 = %p\n",&Base1::val1);
    printf(
    "&Base2::val2 = %p\n",&Base2::val2);
    printf(
    "&Derived::val1 = %p\n",&Derived::val1);
    printf(
    "&Devrived::val2 = %p\n",&Derived::val2);

    cout
    << &Base1::val1 << endl;
    cout
    << &Base2::val2 << endl;
    cout
    << &Derived::val1 << endl;
    cout
    << &Derived::val2 << endl;

    cout
    << "--------------" << endl;
    printf(
    "&Derived2::val1 = %p\n",&Derived2::val1);
    printf(
    "&Devrived2::val2 = %p\n",&Derived2::val2);
    printf(
    "&Derived2::val = %p\n", &Derived2::val3 );

    cout
    << &Derived2::val1 << endl;
    cout
    << &Derived2::val2 << endl;
    cout
    << &Derived2::val3 << endl;
    return 0;
    }

      运行结果如下:GCC和VC下都是同样的结果

    可以看出的是 在c++中cout 和printf 输出的结果竟然还是不一样的 == ,应该是 C++重载了 <<运算符,使<<能够适应各种输出的原因吧

     int Base2::* bmp = &Base2::val2;//Base2::* 型的变量
    cout << bmp << endl;

    通过 cout 可以看出这里输出的就是1,但是 在GCC下 不能转化为 int型的,所以才有了调用   func1(bmp,pd); 并在函数中 cout << pd->*dmp << endl; 时得到了 一个随机数 
    对于C++对象模型中所说的 &Base1::val1 中val 指的是 val在类的对象中的偏移量问题,只能通过printf("&Base1::val1 = %p\n",&Base1::val1);看到,cout 方式可能还是因为重载的缘故吧:所有的输出都是1(不知道原因,可能不是偏移量了吧)
    printf("&Devrived::val2 = %p\n",&Derived::val2); 对于&Derived::val2实际的偏移量应该是4,可能由于编译器的优化,输出为0了。。(怎么优化的? 想不明白)
     书中以   printf("&Derived2::val = %p\n", &Derived2::val3 ); 打印出了 val3的偏移量为8,可以看出

    3. 那个point2d,3d问题
    #include <iostream>
    #include
    <stdio.h>
    using namespace std;
    class Point3d
    {
    public:
    virtual ~Point3d();
    Point3d(
    float a,float b,float c)
    {
    x
    = a;
    y
    = b;
    z
    = c;
    // origin(x,y,z);
    }
    static Point3d origin;
    static void f()
    {
    //error: request for member 'x' in 'Point3d::origin',
    //which is of non-class type 'Point3d()'
    //printf("&origin.x = %p\n",&(origin.x));
    //printf("&origin.y = %p\n",&origin.y);
    //printf("&origin.z = %p\n",&origin.z);
    // printf("&origin = %p\n",&origin);
    }
    float x,y,z;
    };

    int main()
    {
    float f = 1.0;
    cout
    << sizeof(f) << endl;
    cout
    << sizeof(float) << endl;
    cout
    << sizeof(double) << endl;
    printf(
    "&Point3d::x = %p\n",&Point3d::x);//计算的是偏移量 4
    printf("&Point3d::y = %p\n",&Point3d::y);//4 ,结果是8
    printf("&Point3d::z = %p\n",&Point3d::z);//4 结果是C(12)

    cout
    << "&Point3d::x = " << &Point3d::x << endl;
    cout
    << "&Point3d::y = " << &Point3d::y << endl;
    cout
    << "&Point3d::z = " << &Point3d::z << endl;
    //undefined reference to `Point3d::origin'
    // printf("&origin.x = %p\n",&(Point3d::origin.x));
    // printf("&origin.y = %p\n",&Point3d::origin.y);
    // printf("&origin.z = %p\n",&Point3d::origin.z);
    Point3d p();

    //Point3d::f();


    return 0;
    }
    木有打印出来 origin.x ,错误是 
    (1) //undefined reference to `Point3d::origin' ,
    (2)//error: request for member 'x' in 'Point3d::origin',
            //which is of non-class type 'Point3d()'

    virtual ~Point3d(); 去掉虚函数~,变为 Point3d()并完成初始化后:Point3d Point3d::origin(1,1,1);

    #include <iostream>
    #include
    <stdio.h>
    using namespace std;
    class Point3d
    {
    public:
    ~Point3d(){};
    Point3d(
    float a,float b,float c)
    {
    x
    = a;
    y
    = b;
    z
    = c;
    }
    static Point3d origin;

    float x,y,z;
    };
    Point3d Point3d::origin(
    1,1,1);
    int main()
    {
    float f = 1.0;
    cout
    << sizeof(f) << endl;
    cout
    << sizeof(float) << endl;
    cout
    << sizeof(double) << endl;
    printf(
    "&Point3d::x = %p\n",&Point3d::x);
    printf(
    "&Point3d::y = %p\n",&Point3d::y);
    printf(
    "&Point3d::z = %p\n",&Point3d::z);

    cout
    << "&Point3d::x = " << &Point3d::x << endl;
    cout
    << "&Point3d::y = " << &Point3d::y << endl;
    cout
    << "&Point3d::z = " << &Point3d::z << endl;
    //undefined reference to `Point3d::origin'
    printf("&origin.x = %p\n",&(Point3d::origin.x));
    printf(
    "&origin.y = %p\n",&Point3d::origin.y);
    printf(
    "&origin.z = %p\n",&Point3d::origin.z);

    //Point3d::f();


    return 0;
    }

      

    结果如下:

    对比与 两个图中的 &Point3d::x 值得出结论:

    在GCC编译器中,如果加了 virtual ,它的对象布局中应该是 vptr在 数据成员的上面

    而不是像 c++对象模型 cfont 编译器中在数据成员下面



      



  • 相关阅读:
    20150216 IMX257实现GPIO-查询按键驱动程序
    20150216简单的Linux字符设备驱动程序
    Linux内核驱动编程
    解决安装完centos6.6之后/etc/sysconfig/目录下没有iptables 的问题
    centos6.6安装配置jboss7.1.1
    mysql5.6中 order by 多个字段排序问题
    centos6.6编译安装lnmp系列之PHP
    centos6.6编译安装lnmp系列之nginx
    centos6.6编译安装lnmp系列之mysql
    mysq 安装时候进行生成数据库系统时候执行语句 ./scripts/mysql_install_db --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql 时候报错
  • 原文地址:https://www.cnblogs.com/hitwtx/p/2160647.html
Copyright © 2020-2023  润新知