IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 成员函数相关问题 -> 正文阅读

[C++知识库]成员函数相关问题

关于类成员函数

  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. 但对于没有虚函数成员对象,共享内存间是可以直接取用的,因为成员函数地址在编译时已经确定,不需要额外保存指向虚函数表的数据,即使他们函数地址在各进程里不一样。
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-11 21:57:07  更:2022-03-11 21:58:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:00:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码