c++ 由类型转换引起的指针偏移

简介: 由于转载了另外的转载,且原文暂时未找到,此处无法列出原文地址。 在C语言中,如果对一个指针做类型转换,不会改变这个指针的值,改变的只是对指针的解释方式。

由于转载了另外的转载,且原文暂时未找到,此处无法列出原文地址。


在C语言中,如果对一个指针做类型转换,不会改变这个指针的值,改变的只是对指针的解释方式。但是在C++中,由于一些特性的引入,在对指针做类型转换时,编译器有时不得不对指针做一个偏移,以支持这些特性。下面将具体讨论这些情况。
1. 由虚函数引起的指针偏移
通常在有虚函数的类中,编译器会安插一个vptr,但是对vptr的位置C++语言并未做出明确的规定,就目前的实现来看,有的编译器将vptr放在类的开头,如microsoft的c++编译器,而有的编译器将vptr放在类的末尾,如cfront。
对于将vptr放在类的开头这种编译器,我们考虑如下两个类:

class X {
    int i;     
};
class Y : public X {
    int j;
public:
    virtual void vf();
};


X的内存布局很简单,由于它没有虚函数,所以没有vptr,只有一个int类型的变量i;
而Y的内存布局可能像这样:
vptr
 int i
 int j
对于下面这样的代码:
Y y;
X* pX = &y;
编译器为了保证将Y类型的指针转换为X类型的指针后,指向的是一个有效的X对象,它将不得不做一个偏移,实际的代码可能像这样:
X* pX = (X*)((char*)&y + sizeof(vptr))

2. 由多重继承引起的指针偏移
首先需要说明一下多重继承的内存布局,虽然C++语言未明确做出规定,但目前的多数实现会按照基类声明的顺序依次将每个基类的数据成员顺次放入派生类。例如:
class A {
    int i;
};
class B {
    int j;
};
class C : public A, public B {
    int k
};


C的内存布局可能像这样:
 int i
 int j
 int k
有了这样的布局,很容易就能猜到编译器在做类型转换时对指针做出的偏移,例如
C c;
B* pb = &c;
猜想实际的代码可能是:
B* pb = (B*)((char*)&c + sizeof(A));
对于例子中的情况,上面的猜想是成立的,但对于一般的情况就不成立了。在将C类型的指针转换的时候,这个C类型的指针有可能为空,按上面的转换思路,那空指针也得加一个偏移量了,为了避免这种情况,实际的代码可能会是这样:
B* pb = (pc) ? (B*)((char*)pc + sizeof(A)) : 0; //假设pc是一个指向C的指针

3.由虚继承引起的指针偏移
对 于一般的继承(这里仅指单继承),在不涉及虚函数的情况下,由于编译器的实现多会将基类数据成员排在派生类之前,所以从派生类指针转换为基类指针时,一般 不需要做偏移。但是对于虚继承,情况就不一样了。由于虚基类的地址是在运行时确定的,所以由派生类的指针转换为虚基类的指针时必然会引起偏移。虚基类有多 种实现方式,所以在这儿就先不举例了。可以参考<Inside the C++ Object Model>.
相关文章
|
11天前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
34 4
|
26天前
|
存储 安全 编译器
在 C++中,引用和指针的区别
在C++中,引用和指针都是用于间接访问对象的工具,但它们有显著区别。引用是对象的别名,必须在定义时初始化且不可重新绑定;指针是一个变量,可以指向不同对象,也可为空。引用更安全,指针更灵活。
|
1月前
|
存储 C++
c++的指针完整教程
本文提供了一个全面的C++指针教程,包括指针的声明与初始化、访问指针指向的值、指针运算、指针与函数的关系、动态内存分配,以及不同类型指针(如一级指针、二级指针、整型指针、字符指针、数组指针、函数指针、成员指针、void指针)的介绍,还提到了不同位数机器上指针大小的差异。
38 1
|
1月前
|
存储 编译器 C语言
C++入门2——类与对象1(类的定义和this指针)
C++入门2——类与对象1(类的定义和this指针)
30 2
|
1月前
|
编译器 C语言 C++
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
19 1
|
1月前
|
存储 编译器 数据安全/隐私保护
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解2
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
31 3
|
1月前
|
编译器 C++
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解1
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
46 3
|
1月前
|
存储 安全 编译器
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(一)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
|
1月前
|
存储 C++ 索引
C++函数指针详解
【10月更文挑战第3天】本文介绍了C++中的函数指针概念、定义与应用。函数指针是一种指向函数的特殊指针,其类型取决于函数的返回值与参数类型。定义函数指针需指定返回类型和参数列表,如 `int (*funcPtr)(int, int);`。通过赋值函数名给指针,即可调用该函数,支持两种调用格式:`(*funcPtr)(参数)` 和 `funcPtr(参数)`。函数指针还可作为参数传递给其他函数,增强程序灵活性。此外,也可创建函数指针数组,存储多个函数指针。
|
2月前
|
编译器 C++
【C++核心】指针和引用案例详解
这篇文章详细讲解了C++中指针和引用的概念、使用场景和操作技巧,包括指针的定义、指针与数组、指针与函数的关系,以及引用的基本使用、注意事项和作为函数参数和返回值的用法。
38 3