注意C++中对象指针,慎用void*

原创 2007年10月07日 19:57:00

        由于不同C++编译器对C++对象模型的结构可能是不一样的。比如说,VC++系列是将虚函数表指针放在对象首地址,而GCC系列的编译器则是将虚函数表指针放在对象地址尾部。

        那么下面我将详细讲讲GCC编译器下的对象模型(含虚函数表指针)。

        先看下面这个例子:

 

#include <iostream>
using namespace std;


class A
{
private:

    
int a;
    
public:

    A(
void) : a(0)
    
{
        
    }


    
virtual void Hello(void)
    
{
        cout 
<< "Hello, world!" << endl;
    }

}
;

class B : public A
{
private:

    
int b;
    
public:

    B(
void) : b(1)
    
{
        
    }


    
virtual void Hello(void)
    
{
        cout 
<< "B!" << endl;
    }

}
;

         上面的示例中,A对象的地址中存放两个4字节的数据,一个是变量a,另一个是虚函数表指针。变量a放在低地址;虚函数表指针放在高地址,那么方便起见,我这样表示——A  objA = { a,  vptr  }。而B的对象首先是存放类A域的所有成员,然后是B自己的数据成员——B  objB = { a, vptr, b }。

        那么这样的安排就有助于编译器处理这样的情况了——

 

B b;
*= &b;
b
->Hello();

 

        那么如果是多继承或是虚继承会怎样呢?

        碰到这种情况,GCC或其兼容C++编译器会同时判断左操作数的类型以及有操作数的类型。根据左操作数的类型来判断左操作数的指针指向有操作数对象的哪个偏移地址。如果是其他类型的指针(如void*),则指向对象的首地址。

        下面请看一下详细的测试代码:

 

#include <iostream>
using namespace std;


class A
{
private:

    
int a;
    
public:

    A(
void) : a(0)
    
{
        
    }


    
virtual void Hello(void)
    
{
        cout 
<< "Hello, world!" << endl;
    }

}
;


class AA
{
private:

    
int aa;
    
public:

    AA(
void) : aa(100)
    
{
        
    }

    
    
virtual void Hi(void)
    
{
        cout 
<< "Hi, therte!" << endl;
    }

}
;


class B : public A
{
private:

    
int b;
    
public:

    B(
void) : b(1)
    
{
        
    }


    
virtual void Hello(void)
    
{
        cout 
<< "B!" << endl;
    }

}
;


class C : virtual public A
{
private:

    
int c, d;
    
public :

    C(
void) : c(2), d(3)
    
{
        
    }

    
    
void Hello(void)
    
{
        cout 
<< "C!" << endl;
    }

}
;


class E : public A, public AA
{
private:

    
int e;
    
public:

    E(
void) : e(8)
    
{
        
    }

    
    
void Hello(void)
    
{
        cout 
<< "E!" << endl;
    }

    
    
void Hi(void)
    
{
        cout 
<< "Hi!" << endl;
    }

}
;


extern "C" void test(void);


int main(void)
{
    A a;
    B b;
    C c;
    E e;
    
    unsigned 
long s[10];
    
    
int i=0;
    
    
for(; i<sizeof(a) >> 2; i++)
        s[i] 
= ((unsigned long*)&a)[i];
        
    a.Hello();
    
    
for(i=0; i<sizeof(b) >> 2; i++)
        s[i] 
= ((unsigned long*)&b)[i];
        
    A 
*= &b;
    
    p
->Hello();
    
    
for(i=0; i<sizeof(c) >> 2; i++)
        s[i] 
= ((unsigned long*)&c)[i];
        
    p 
= &c;
    
    
void* q = (C*)&c;
    
    p
->Hello();
    
    
for(i=0; i<sizeof(e) >> 2; i++)
        s[i] 
= ((unsigned long*)&e)[i];
        
    AA 
*pp = &e;
    p 
= &e;
    q 
= &e;
    
    
return 0;
}

 

        在main函数中,上面的p和q两个指针的值是不同的,尽管它们指向同一个对象。p指向了对象c的A类域的偏移处;而q则是指向了p 的首地址。那么下面的pp和p及q也是不同,这里的p和q都是指向首地址,因为类A域在对象e的起始处,而pp则是指向了e的AA类域的偏移处。

        大家可以利用以上代码进行调试,有个感性认识。

        所以在C++中,甚用void*指针指向一个对象,否则当再次进行类型转换时,调用相关函数可能会发生意想不到的情况。那么这个时候还是利用模板,通过范型来解决类型问题,这样做更安全,而且更优美。

相关文章推荐

C++对象的地址

1、对象的地址是该对象拥有的所有地址中的最小地址; 2、每个类中的非静态成员变量的声明顺序将会决定其地址值的大小,声明越靠后,地址值越大; 3、继承和虚继承会影响父类和子类地址的分配顺序; 4、...

C++多重继承与void*指针转换问题

C++支持多重继承,然而多重继承可能会导致一些奇怪的问题,我前段时间遇到一个指针转换问题,非常典型。...
  • foruok
  • foruok
  • 2016年03月05日 07:29
  • 3151

C++得到成员变量的偏移值

一:零地址转换 以下为MFC常用宏: #define OFFSET(structure, member) ((int)&((structure*)0)->member); ...

移动端身份证识别app如何

移动端身份证识别app应用背景   移动端身份证识别app的应用,让需要实名制的应用更加方便,快捷,提高用户体验,为人们解决繁琐输入的问题,随着智能终端(智能手机及平板电脑)及移动通信(4G)的发展...

C++11标准之右值引用(rvalue reference)

一篇关于右值引用不错的文章,在必要的地方加了自己的见解,如果有误请指教。 转载自http://www.cnblogs.com/soaliap/archive/2012/11/19/2777131.h...

C++ void指针解析

指针的解析:       指针有两个属性:指向变量/对象的地址和长度 ,但是指针只存储地址,长度则取决于指针的类型 ,编译器根据指针的类型从指针指向的地址向后寻址 ,指针类型不同则寻址范围也不同,比如...

C++, ID、指针、handle (void *)的区别

在Windows程序设计中,句柄是无法精确定义的术语。随便找一个高手,让他给你讲讲句柄是什么,恐怕他都很难给你一个具体的定义来。 在Windows程序设计中,句柄无所不在,窗口有窗口的句柄HWND,...

C/C++下void*类型指针介绍

写C/C++程序经常会遇到void*类型的指针,以前对于这个指针

C++语言复习七 数组的memset初始化 void指针的用法 举例

对于数组a[10]; a则为数组的首地址,其实就是一个 指向a[0]常指针。 则可以用: *(a+1) = a[1];  *(a+n)=a[n]; 注意: 用*(a++) 表示 a[1];...

关于void指针的注意要点和使用

void在英文中作为名词的解释为“空虚;空间;空隙”;而在C语言中,void被翻译为“无类型”,相应的void *为“无类型指针”。void似乎只有“注释”和限制程序的作用,当然,这里的“注释”不是为...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:注意C++中对象指针,慎用void*
举报原因:
原因补充:

(最多只允许输入30个字)