父类指针可以指向子类对象,是安全的(继承方式必须是public)
struct Person {
int m_age;
};
struct Student : Person {
int m_score;
};
int main() {
// 父类指针 指向 子类对象
Person *P = new Student();
getchar();
return 0;
}
-
父类的只能访问部分空间,是安全的
-
如果是子类的,真正访问过去时父类只有一个变量。造成溢出赋值到其他空间了
多态-传进去的对象不同,调用不同对象的函数就叫做多态
- 我看视频,知道整个过程的发生,教的人图文并茂外加手指吸引注意力观察什么地方,最后写下描述的定义和结论,这叫学习。
- 结果又来一人,他只看见我写的这个结论,外加下面代码,这像不像是课本上面的定理与文字解释?对不起,你不知道观察哪里去发现。
- 我们需要深思,学习方式与学习环境。所以,你会发现我的大部分文章保留有原创的资料,为的就是尽量把学习环境给还原出来。
...
void liu(Animal *p) {
p->speak();
p->run();
}
int main() { //子类的对象传给上面父类的指针
liu(new Dog());
liu(new Cat());
liu(new Pig());
...
}
默认汇编只根据左边的类型来调用函数,不存在多态
int main() {
Animal *p = new Dog();
p->speak(); // call Animal::speak
p->run(); // call Animal::run
}
C++中的多态通过虚函数(virtual function)来实现
虚函数:被virtual修饰的成员函数
只要在父类中声明为虚函数,子类中重写的函数也自动变成虚函数
struct Animal {
virtual void speak() { //子类调用时,默认也会变成虚函数
cout << "Animal::speak()" << endl;
}
virtual void run() {
cout << "Animal::run()" << endl;
}
};
struct Dog : Animal {
void speak() { //这里继承后,默认变成虚函数,写不写都可以
。。。
} 。。。
};
int main() {
Animal *p = new Dog();
p->speak(); // call eax 使用虚函数后,这里变成调用后面的Dog,用寄存器实现了多态
p->run(); // call eax 机器码不一样了FF开头(间接),不是E8开头(直接)
}
``` //这些机器码对应什么意思,从哪里来的?intel白皮书。什么人看这些机器码?破解与外挂
# 多态的要素,C++多了一个虚函数
* 子类重写父类的成员函数
* 父类指针指向子类对象
* 利用父类指针调用重写的成员函数
* 注意以上要素,都是翻译过来,自己总结的东西,属于术语层面的东西,不必在这里面过多的扣字考古。掌握本质可以写出各种花里胡哨的术语,总结。学的是来龙去脉,而不是学几个术语是啥意思。
# 虚表
* 虚函数的实现原理是虚表,虚表里面存储着最终需要调用的虚函数地址,这个虚表也叫虚函数表
# 调用父类的成员函数
struct Cat : Animal {
void speak() {
Animal::speak();
...
}
}