成员函数相关问题

关于类成员函数

  1. 类的大小本身不会包含类成员函数的指针地址,
class TestASize {
	int id = 444;
};

class TestBSize {
public:
	int id = 232;
	void test1() {}
	void test2() {}

};

int main()
{
	TestBSize b;
	TestASize a;
	std::cout << "a size: " << sizeof(a) << std::endl;
	std::cout << "b size: " << sizeof(b) << std::endl;

	std::cout << "TestASize: " << sizeof(TestASize) << std::endl;
	std::cout << "TestBSize: " << sizeof(TestBSize) << std::endl;
}

打印结果为:
a size: 4
b size: 4
TestASize: 4
TestBSize: 4

  1. 成员函数是独立保存的,多个对象可以共用(在win里,甚至相同进程,也是一样的)

成员函数的指针地址不能通过std::cout打印,因为没有针对(__thiscall Class:: *)()类型重载operator<<
但可以通过printf, 使用%p打印

	printf("TestBSize::test1: %p\n", &TestBSize::test1);
	printf("TestBSize::test2: %p\n", &TestBSize::test2);

打印结果:
TestBSize::test1: 00E2143D
TestBSize::test2: 00E2144C

成员虚函数

  1. 当存在类中存在虚函数时,就会生成虚函数表
  2. 虚函数表是共用的,每个对象都会保存其指向虚函数的指针
#include <iostream>

class A {
public:
    virtual void test() {
        std::cout << "A::test" << std::endl;
    }
    int ai = 0;// 4
};

class B : public A{
public:
    void test() override { // 4
        std::cout << "B::test" << std::endl;
    }

    int bi = 1212; // 4
};


int main()
{
    A a, a2;
    B b, b2;
    printf("a size: %i, \n b size: %i\
            \n", sizeof(a), sizeof(b));

}

打印结果为:
a size: 8,
b size: 12

a的大小= vptr +int = 8
b的大小 = vptr + int + int = 12

  1. 虚表一般保存在对象首位

可以使用如下方式获取

#define GET_VTABLE(c) (int*)(*(int*)(&(c)))

获得虚表后,如果我们甚至可以直接遍历里面的方法

typedef void (*FUNC)();
void PrintVTable(int* vtable) {
    std::cout << " vptr: " << vtable;
    for (int i = 0; vtable[i] != 0; ++i) {
        printf("\n%i, virtual fun addr %p \n", i, vtable[i]);
        FUNC f = (FUNC)vtable[i];
        f();
    }
    std::cout << std::endl;
}
int main()
{
    A a, a2;
    B b, b2;

    PrintVTable(GET_VTABLE(a));
    PrintVTable(GET_VTABLE(a2));
    PrintVTable(GET_VTABLE(b));
    PrintVTable(GET_VTABLE(b2));
}

vptr: 00349B34
0, virtual fun addr 0034103C
A::test
vptr: 00349B34
0, virtual fun addr 0034103C
A::test
vptr: 00349B4C
0, virtual fun addr 0034114A
B::test
vptr: 00349B4C
0, virtual fun addr 0034114A
B::test

进程间共享内存的问题

  1. 对于存在虚函数的类,由于存在虚函数表,表是与进程相关的,故每个进程里的虚表地址不一定是一样的

有两个进程,他们都有如下数据

class TestSharedData {
public:
	virtual void test_print() {
		std::cout << "TestSharedData::test_print: " << i;
	}
	int i = 23232;
};

class TestSharedDataB : public TestSharedData {
public:
	void test_print() override {
		std::cout << "TestSharedDataB::test_print : " << i;
	}
};

进程a跑如下方法

// test for shared memory
static void test_shared_a() {
	char szBuffer[] = "";
	const char* test_str = "This is a shared memory test!!!";

	// 创建共享文件句柄
	HANDLE hMapFile = CreateFileMapping(
		INVALID_HANDLE_VALUE, // 物理文件句柄
		NULL, // 默认安全级别
		PAGE_READWRITE, // 可读可写
		0, // 高位文件大小
		BUFF_SIZE, // 地位文件大小
		shared_mem_name // 共享内存名称
	);

	LPVOID lpBase = MapViewOfFile(
		hMapFile, // 共享内存的句柄
		FILE_MAP_ALL_ACCESS, // 可读写许可
		0,
		0,
		BUFF_SIZE
	);

	EDataChunk::instance().init((char*)lpBase, BUFF_SIZE);
	{
		char* test_ptr = EDataChunk::instance().allocate(sizeof(TestSharedDataB));
		TestSharedDataB* b = new(test_ptr) TestSharedDataB();
		PrintVTable(GET_VTABLE(*b));

		b->test_print();
		int temp = 232;
		std::cin >> temp;
		b->~TestSharedDataB();
		EDataChunk::instance().deallocate(test_ptr);
	}

	EDataChunk::instance().uninit();


	UnmapViewOfFile(lpBase);
	CloseHandle(hMapFile);
}

进程b跑如下函数

static void test_shared_b() {
	// 打开共享的文件对象
	TestSharedDataB b;
	PrintVTable(GET_VTABLE(b));
	HANDLE hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, NULL, shared_mem_name);
	if (hMapFile)
	{
		LPVOID lpBase = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
		// 将共享内存数据拷贝出来

		TestSharedDataB* a = (TestSharedDataB*)lpBase;
		PrintVTable(GET_VTABLE(*a));
		// 解除文件映射
		UnmapViewOfFile(lpBase);
		// 关闭内存映射文件对象句柄
		CloseHandle(hMapFile);
	}
}

a 进程下有如打印:
vptr: 0146ABF4
virtual fun addr 013F4F91
data vtable addr:0146ABF4
TestSharedDataB::test_print: 23232

b 会报错,但也会有如下打印:
vptr: 00B79BA0
virtual fun addr 00B714B5
data vtable addr:0146ABF4

可以看出,a,b 进程下,TestSharedDataB对象的虚函数表指向是不一致,所以是不能在进程间直接使用同一个对象

  1. 但对于没有虚函数成员对象,共享内存间是可以直接取用的,因为成员函数地址在编译时已经确定,不需要额外保存指向虚函数表的数据,即使他们函数地址在各进程里不一样。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值