22.多态(下)

多态原理:

虚函数表指针实际叫函数指针数组

这是虚函数表指针,这是个指针指向这张表也就是指向这个数组。

cpp 复制代码
class Person {
public:
	void BuyTicket() { cout << "买票-全价" << endl; }
protected:
	string _name;
};

class Student : public Person {
public:
	virtual void BuyTicket() { cout << "买票-打折" << endl; }

protected:
	int _id;
};

class Soldier : public Person {
public:
	virtual void BuyTicket() { cout << "买票-优先" << endl; }

protected:
	string _codename; // 代号
};

void Func(Person* ptr)
{
	// 这里可以看到虽然都是Person指针Ptr在调用BuyTicket
	// 但是跟ptr没关系,而是由ptr指向的对象决定的。
	ptr->BuyTicket();
}

int main()
{
	// 其次多态不仅仅发生在派生类对象之间,多个派生类继承基类,重写虚函数后
	// 多态也会发生在多个派生类之间。
	Person ps;
	Student st;
	Soldier sr;

	Func(&ps);
	Func(&st);
	Func(&sr);

	return 0;
}

各类的虚函数表有各自的虚函数,继承父类还有自己的成员。

怎么样能指向谁调用谁,编译器检查语法也是看满足多态吗,满足,编译这段指令时候就把这段指令变成 到指针指向这个对象的里面的虚表去找,

这个ptr无论传谁我看到的都是父类,

无论ptr指向person student codename 看到的都是person,切片以后看到的也是person,只是有可能是person,也有可能是子类切片切出来的person对象。汇编转换成指令是指针找到对象,去这个对象四个字节或者八个字节据情况而定取这个指针,通过这个指针找到函数指针的数组,这个表,在这个表里找到虚函数

父类是父类虚函数,子类是子类重写的虚函数。

person的virtual去掉就不满足多态

满足多态生成一组汇编,不满足多态生成一组汇编。不满足多态跟指向就无关,调用的都是父类

左边就是通过虚函数表指针不断找,调用

父类虚表放父类虚函数子类虚表放子类虚函数。某种程度上这也是重写的意义,执行的指令一样,但是对象的续表不一样,所以指向不同对象调用不同虚函数。

为甚不把虚函数直接放对象而放到一个表,因为很多对象可共享。同类型虚函数表是一样的,否则太冗余。

派生类的虚函数表指针是他继承的基类那一部分继承下来的,那一部分指针跟基类是不一样的。

继承类的虚函数表先把基类的虚函数表复制,然后继承类有重写的,就覆盖,没重写的就加进去,加进去的vs看不了,调用内存看,

第三个很接近,基本上确定是

拿到对象的头四个字节,就是虚函数表的地址,

强转成int* 解引用就是看头上四个字节,头上四个字节值就是指向虚表 的地址,

cpp 复制代码
int main()
{
	int i = 0;
	static int j = 1;
	int* p1 = new int;
	const char* p2 = "xxxxxxxx";
	printf("栈:%p\n", &i);
	printf("静态区:%p\n", &j);
	printf("堆:%p\n", p1);
	printf("常量区:%p\n", p2);

	Base b;
	Derive d;
	Base* p3 = &b;
	Derive* p4 = &d;
	printf("Person虚表地址:%p\n", *(int*)p3);
	printf("Student虚表地址:%p\n", *(int*)p4);
	printf("虚函数地址:%p\n", &Base::func1);
	printf("普通函数地址:%p\n", &Base::func5);
	return 0;
}

打印虚函数和普通函数就,是为了证明,他两在一个区域。只是虚函数地址又放到了虚表里面,成员函数取地址前面加&。

可以认为虚函数在VS下放到常量区

放到栈肯定不合理,函数结束,虚表销毁,两个函数,一个函数结束虚表销毁,不行。堆可以也不太合理,动态开辟没人去释放,系统自动释放倒是可以,静态区常量区更合理。取决于开发人员

相关推荐
阿正的梦工坊11 分钟前
【Rust】09-泛型、Trait 与生命周期基础
开发语言·rust·c#
阿正的梦工坊35 分钟前
【Rust】07-错误处理:Option、Result 与 ? 运算符
开发语言·算法·rust
Zella折耳根39 分钟前
复习篇-继承和接口
java·开发语言·python
z落落42 分钟前
C# 事件(Event)+自定义带参数事件例子
开发语言·分布式·c#
FlYFlOWERANDLEAF42 分钟前
DevExpress Office File API使用记录
开发语言·c#·devoffice
程序员二叉1 小时前
【JVM】OOM详解+JVM参数+FullGC排查+CPU飙高+死锁+内存泄漏+命令大全
java·开发语言·jvm·面试
yijianace1 小时前
Python线程与多线程完全总结(从入门到理解并发本质)
开发语言·python
不知名的老吴1 小时前
线程的生命周期之线程同步
java·开发语言·jvm
为何创造硅基生物1 小时前
独占指针的创建std::make_unique 本身自带堆出现
c++