注意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++:函数传指针(void * xx)、传引用(void & xx)和传指针的引用(void *& xx)

1。函数的形参是指针类型void func(int * arg) void func(int * arg) { *arg = 15; } main() { ...
  • qq_30968657
  • qq_30968657
  • 2016年07月06日 11:15
  • 1755

C++实现字符串替换的两种方法

#includestring> #include using namespace std; //第一种替换字符串的方法用replace() void string_replace(string&s...
  • yockie
  • yockie
  • 2016年06月29日 22:36
  • 631

c++中 void*的使用

说明指针变量包含两个信息,地址和数据的类型。而void*是一种特殊的指针,其只包含地址而不包含类型。 int a; void *vpa = &a; //可以 int *ipa ...
  • autoliuweijie
  • autoliuweijie
  • 2016年03月23日 19:08
  • 292

C++如何向函数传递对象

一.值传递 函数中如果对对象进行了修改,对象的值不变;相当于创建对象的一个副本传递给函数 #include using namespace std; class Test { public...
  • u012967763
  • u012967763
  • 2015年01月03日 16:17
  • 231

C++ 通过引用来传递和返回对象

提高效率 #include using namespace std; class C{ public: void set(int n){num=n;} int get() const {retu...
  • Slience_Perseverance
  • Slience_Perseverance
  • 2014年02月28日 14:29
  • 2210

C++中void和void*指针的含义

转载:http://blog.chinaunix.net/uid-22197900-id-359211.html 转载:http://www.jb51.net/article/36570.htm   ...
  • Lee_Shuai
  • Lee_Shuai
  • 2016年11月17日 00:12
  • 6961

空指针和void *类型指针

今天,有个师弟问我:“师兄,空指针和void *类型指针是怎样的?” 当时,我大概的说法是: 1、空指针是没有指向的指针,将暂时用不到的指针定义成空指针,能防止误用。 2、而void * 类型的指针是...
  • luo_technically
  • luo_technically
  • 2016年10月01日 01:12
  • 1475

妙用void *型指针(万能指针|泛型指针)

为什么叫万能指针呢?
  • wusuopuBUPT
  • wusuopuBUPT
  • 2014年09月02日 19:15
  • 4201

void指针详解

void指针的理解和使用都是比较复杂的,尤其与其他形式定义结合时,就显得更为复杂了。下面就综合网上一些资料,介绍一下void的用法。 1.void指针是一种特别的指针    void *vp ...
  • zycxnanwang
  • zycxnanwang
  • 2016年10月20日 21:13
  • 1184

C语言指针高级部分:void指针和数据指针

概念 void指针 数据指针 void指针void指针的基本概念void的意思就是“无类型”,void指针则为“无类型指针”,void指针可以指向任何类型的数据。 所以void指针一般被称为通用指针或...
  • qq_29924041
  • qq_29924041
  • 2017年02月05日 17:50
  • 1065
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:注意C++中对象指针,慎用void*
举报原因:
原因补充:

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