c++类及其布局和转换
c++ Classes and their layouts and conversions
我得到了这个代码来测试我的cpp理解,我很困惑:
#include "stdafx.h"
#include <iostream>
#include <cstddef>
using namespace std;
class A
{
public:
A() : m_x(0) { }
public:
static ptrdiff_t member_offset(const A &a)
{
const char *p = reinterpret_cast<const char*>(&a);
const char *q = reinterpret_cast<const char*>(&a.m_x);
return q - p;
}
private:
int m_x;
};
class B
: public A
{
public:
B() : m_x('a') { }
public:
static int m_n;
public:
static ptrdiff_t member_offset(const B &b)
{
const char *p = reinterpret_cast<const char*>(&b);
const char *q = reinterpret_cast<const char*>(&b.m_x);
return q - p;
}
private:
char m_x;
};
int B::m_n = 1;
class C
{
public:
C() : m_x(0) { }
virtual ~C() { }
public:
static ptrdiff_t member_offset(const C &c)
{
const char *p = reinterpret_cast<const char*>(&c);
const char *q = reinterpret_cast<const char*>(&c.m_x);
return q - p;
}
private:
int m_x;
};
int _tmain(int argc, _TCHAR* argv[])
{
A a;
B b;
C c;
std::cout << ((A::member_offset(a) == 0) ? 0 : 1);
std::cout << ((B::member_offset(b) == 0) ? 0 : 2);
std::cout << ((A::member_offset(b) == 0) ? 0 : 3);
std::cout << ((C::member_offset(c) == 0) ? 0 : 4);
std::cout << std::endl;
return 0;
}
答案是0204。前三个案例我懂了,但最后一个我不懂。最后一个和第一个的区别是一个虚析构函数。这有关系吗?如果是,怎么做?
代码示例有一个实现定义的行为。不能保证任何情况下的输出。而不是保证类的成员总是被放置在连续的内存位置。它们之间可以添加填充字节。是否添加填充作为实现细节被忽略。你对virtual
起作用的怀疑可能是真的[注1]。但重要的是要注意的是,即使没有virtual
,输出也不能保证。
c++ 11.9.2类成员[Class .mem]
14)具有相同访问控制(第11条)的(非联合)类的非静态数据成员是这样分配的以后的成员在类对象中拥有更高的地址。非静态数据的分配顺序具有不同访问控制的成员未指定(11)。实现对齐要求可能导致两个相邻的成员不能在彼此之后立即分配;所以对管理虚函数(10.3)和虚基类(10.1)的空间。
<一口>[注1]:一口>
动态调度本身是一种实现定义的机制,但是大多数(读所有已知的)实现使用虚表和指针机制来实现它。对于多态类(不从任何其他类派生),通常虚指针存储为类的第一个元素。因此,可以合理地假设,在最后一种情况下,当您在环境中运行代码示例时,这就是在幕后发生的事情。
在线样本:
#include<iostream>
using std::cout;
using std::endl;
class B;
typedef void (*HANDLE_DOSOMETHING)(B *const, int q);
class B
{
public:
virtual void doSomething(int q)
{
std::cout<<"B::doSomething()"<<q<<endl;
}
void dummy()
{
HANDLE_DOSOMETHING *f1ptr = NULL;
int *vtbl = NULL;
int *vptr = (int *)this; // address of the object
vtbl = (int *)*vptr; //address of the VTABLE
f1ptr = (HANDLE_DOSOMETHING *)&(vtbl[0]); //address of the 1st virtual function
(*f1ptr)(this, 55);
}
};
int main()
{
B objb;
objb.dummy();
return 0;
}
输出:B::doSomething()55
是的,虚成员函数(在本例中是析构函数)保存在虚函数表中,虚函数表通常作为类数据结构的第一个元素存储。
但是,请注意c++标准中没有严格的规则规定这种情况
相关文章:
- 防止主数据类型C++的隐式转换
- 模板参数替换失败,并且未完成隐式转换
- 努力将整数转换为链表。不知道我在这里做错了什么
- HEX值到wchar_t字符(UTF-8)的转换
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将 Qvector<uint8_t> 转换为 QString
- 如何在cuSparse中使用cusparseXcoo2csr从coo转换为csc
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 在c++中使用nlohmann从类到json的转换
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 将Integer转换为4字节的unsined字符矢量(按大端字节顺序)
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 如何使用OpenCV将RBG图像转换为HSV,并将H、S和V值保存为C++中的3个独立图像
- 复制列表初始化的隐式转换的等级是多少
- 可以通过强制转换到布局兼容的类型来访问私有成员函数
- 布局中的 Qt 状态机转换
- c++中向下转换过程中的内存布局
- 具有相同布局的不同类型之间的c++转换
- 转换为具有相同数据成员布局但实现不同的类是否安全?
- c++类及其布局和转换