本文内容来自于对狄泰学院 唐佐林老师 C++深度解析 课程的学习总结
父子间的赋值兼容
子类对象可以当作父亲对象使用(兼容性)
子类对象可以 直接赋值 给父类对象
子类对象可以 直接初始化 父类对象
父类指针 可以 直接指向 子类对象
父类引用 可以 直接引用 子类对象
编程实验
编写一个Parent类和一个Child类,Child类继承Parent类
#include <iostream>
using namespace std;
class Parent
{
public:
int m_p;
void func(int i)
{
m_p = i;
}
void func(int i, int j)
{
m_p = i + j;
}
};
class Child : public Parent
{
public:
int m_c;
void func(int i, int j, int m)
{
m_c = i + j + m;
}
};
在 main 中做如下操作
编译没有报错,说明第 33行,34行,35行是合法的。
我们再来改写程序,增加第37行和38行代码,用指向Child类对象的Parent类对象指针访问Child类对象成员
编译结果
编译报错,提示Parent 类中没有对应的成员变量和成员函数
通过实验得出如下结论
当使用父类指针(引用)指向子类对象时
1.子类对象 退化为父类对象
2.只能访问 父类中定义的成员
3.可以 直接访问 被子类 覆盖的 同名成员
特殊的同名函数
子类中可以 重定义 父类中 已经存在的成员函数
这种重定义发生在继承中,叫做函数重写
函数重写 是同名覆盖的一种特殊情况
思考
当 函数重写 遇上 赋值兼容 会发生什么?
编写一段实验程序来看下现象
#include <iostream>
using namespace std;
class Parent
{
public:
int m_p;
void func(int i)
{
m_p = i;
}
void func(int i, int j)
{
m_p = i + j;
}
void printf()
{
cout << "I'm Parent" << endl;
}
};
class Child : public Parent
{
public:
int m_c;
void func(int i, int j, int m)
{
m_c = i + j + m;
}
void printf()
{
cout << "I'm Child" << endl;
}
};
void print(Parent *p)
{
p->printf();
}
int main(void)
{
Child c;
Parent p = c;
Parent *p1 = &c;
Parent& p2 = c;
print(&p);
print(&c);
return 0;
}
运行结果
实验现象,当子类调用print函数时调用的竟然是父类的printf函数
问题分析
编译期间,编译器只能根据指针的类型判断 所指向的对象
根据赋值兼容,编译器认为父类指针指向的是父类对象
因此,编译结果只可能是 调用父类中定义的同名函数
小结
子类对象可以当作父类对象使用(赋值兼容)
父类指针可以 正确的指向子类对象
父类引用可以 正确的代表子类对象
子类中可以 重写 父类中的 成员函数