C++多重继承内存寻址问题
C++ Multiple Inheritance Memory Addressing issue
请忽略 #include 部分,假设它们正确完成。这也可能是特定于实现的(但 vtables 的概念也是如此),但我只是好奇,因为它增强了我对多重继承的可视化。(顺便说一下,我正在使用MinGW 4.4.0)
初始代码:
class A {
public:
A() : a(0) {}
int a;
};
//Edit: adding this definition instead
void f(void* ptrA) {
std::cout<<((A*)ptrA)->a;
}
//end of editing of original posted code
#if 0
//this was originally posted. Edited and replaced by the above f() definition
void f(A* ptrA) {
std::cout<<ptrA->a;
}
#endif
对此进行编译并生成目标代码。
在我使用的其他编译单元中(在包含上述代码的头文件之后):
class C : public B , public A {
public:
int c;
}objC;
f(&objC); // ################## Label 1
objC 的内存模型:
//<1> stuff from B
//<2> stuff from B
//<3> stuff from A : int a
//<4> stuff from C : int c
&objC
将在上面假设的内存模型中包含 <1> 的起始地址编译器如何/何时将其转换为 <3>?在检查Label 1
呼叫期间是否发生?
编辑::
由于 Lable 1 似乎是一个赠送,只是让它对编译器来说更加晦涩难懂。请参阅上面的编辑代码。现在编译器什么时候做,在哪里做?
是的,你说得很对。
要完全了解情况,您必须在两点上知道编译器所知道的内容:
- 在标签 1(如您已经确定的那样)
-
内部函数 f()
(1) 编译器知道 C 和 A 的确切二进制布局以及如何从 C* 转换为 A*,并将在调用站点执行此操作(标签 1)
(2) 然而,在函数 f() 中,编译器只(需要)知道 A*,因此将自己限制为 A 的成员(在本例中为 int a),并且不能混淆特定实例是否是其他任何实例的一部分。
简短回答:如果编译器知道基类和派生类之间的关系,它将在强制转换操作期间调整指针值。
假设类 C 的对象实例的地址位于地址 100。 假设 sizeof(C) == 4。 sizeof(B) 和 sizeof(A) 也是如此。
发生强制转换时,如下所示:
C c;
A* pA = &c; // implicit cast, preferred for upcasting
A* pA = (A*)&c; // explicit cast old style
A* pA = static_cast<A*>(&c); // static-cast, even better
pA 的指针值将是 c 的内存地址加上 C 中"A"开头的偏移量。 在这种情况下,pA 将引用存储器地址 104,假设 sizeof(B) 也是 4。
所有这些都适用于将派生类指针传递到需要基类指针的函数中。 隐式强制转换将发生,指针偏移量调整也是如此。
同样,对于向下投射:
C* pC = (C*)(&a);
编译器将负责在协同过程中调整指针值。
所有这一切的一个"陷阱"是当一个类在没有完整声明的情况下被向前声明时:
// foo.h
class A; // same as above, base class for C
class C; // same as above, derived class from A and B
inline void foo(C* pC)
{
A* pA = (A*)pC; // oops, compiler doesn't know that C derives from A. It won't adjust the pointer value during assigment
SomeOtherFunction(pA); // bug! Function expecting A* parameter is getting garbage
}
这是一个真正的错误!
我的一般规则。 避免旧的"C 样式"强制转换,而倾向于使用 static_cast 运算符,或者仅依靠隐式强制转换而没有运算符来执行正确的操作(对于向上转换)。 如果强制转换无效,编译器将发出错误。
- 从结构寻址时,MMAP变量的行为很奇怪
- 字节真的是最小可寻址单元吗
- 具有两个间接寻址运算符 (C++) 的函数参数的用途
- imread() 仍然返回空垫子,尽管在 openCV 4.0.0 中寻址正确
- 在具有开放寻址的哈希表中插入节点 [优化逻辑]
- 如何像在 C++ 中处理数组一样对 .txt 文件中的字符进行寻址?
- C++11右值引用寻址
- 对堆栈增长和寻址的困惑
- C++ std::find() 寻址返回向量的类函数时的意外行为
- 间接寻址运算符如何返回带有运算符重载的指针地址
- Adafruit NeoPixel库在寻址超过7个LED灯条时不起作用
- 在模板 SFINAE 约束中使用间接寻址级别会导致硬错误
- 错误:使用索引寻址和 Clang 的指令的操作数无效
- 是否可以寻址另一个网络中的服务器/客户端套接字?(C++)
- C++中的字节寻址算法
- 指针声明和间接寻址之间的区别
- 仅在使用间接寻址时调用虚函数 — 经典的早期绑定问题?
- C++ std::map 不同的键寻址同一索引
- Valgrind 错误:系统调用参数 epoll_pwait(sigmask) 指向不可寻址的字节
- C++多重继承内存寻址问题