1.隐藏
隐藏就是当父类与子类定义相同的成员时,子类从父类继承来的成员会隐藏掉,实例化时调用子类的成员。
如上图在定义两个有继承关系的类后,下图中实例化后红色语句第一行是调用子类的play
,第二行是调用父类的play
。
(1)如果是定义了同名的数据成员需要在子类的成员函数中调用时区分的话,如父类的string code
,与子类的 int code
(同类型也一样)。也可采用上图中的方式code
与Person::code
来区分。(一般命名遵循m_数据类型+变量名不会出现这种问题)
(2)注意有继承关系父子类同名成员函数,即使父类是无参,子类是有参,在实例化后子类调用无参函数也不会调用父类的函数,而会报错。
2.isA
子类可以看做是父类,如隐形眼镜也是眼镜,工人也是人。这种关系看做isA
。
定义了一个父类Person
与子类Soldier
,实例化时如下图。
可以看出实例化对象后,子类可以赋值给父类,父类的指针也可以指向子类的对象,而反过来是错误的。在内存中如下图所示。
当子类对象赋值给父类时,仅仅会将父类与子类公有的成员函数以及数据成员赋值给父类,子类自己的数据成员等(如图中m_strCode
)是不会给父类的。在用指针时,父类的指针也仅能指向子类与父类公有的成员。
(1)虚析构函数
此外,当父类指针用堆的方法指向子类 如 Person *p=new Solider
,在销毁指针p
的时候子类的内存不会释放,这个时候需要构造虚析构函数。
父类 virtual ~Person()
子类 virtual ~Soldier()
(子类的virtual可不写)
详见 https://blog.csdn.net/zhoujy1996/article/details/80556115
(2)isA的应用
可以将父类的对象作为形参,这样子类和父类都可以作为实参传入。如下图。
图中,fun1形参是父类的对象指针,fun2形参是父类的对象引用。右边图像是父子类的对象都可以作为实参传入。
(3)代码例子
定义如下两个父子类,以及分别将类的对象、对象引用、对象指针作为形参的三个函数。
#include <iostream>
#include<stdlib.h>
#include <string>
using namespace std;
//定义父类
class Person
{
public:
Person(string name = "jim")
{
m_strName = name;
cout << "Person()" << endl; }
virtual ~Person() { cout << "~Person()" << endl; } //虚析构函数
void play() { cout << "person--play--"<<m_strName << endl; }
protected:
string m_strName ;
};
//定义公共继承的子类
class Soldier : public Person
{
public:
Soldier(string name = "jame")
{
m_strName = name;
cout << "Solider()" << endl; }
~Soldier() { cout << "~Soldier()" << endl; }
void play() { cout << "Soldier--play--"<<m_strName << endl; }
protected:
//string m_strName; 这里博主加了这句,最后结果都会显示jim,不太清楚为什么,有知道的希望能说一下
};
//定义调用函数
void text1(Person p) //形参为对象
{
p.play();
}
void text2(Person &p) //形参为引用
{
p.play();
}
void text3(Person *p) //对象为指针
{
p->play();
}
①实参为对象
int main(void)
{
Person p;
Soldier s;
text1(p);
text1(s);
system("pause");
return 0;
}
可见在实例化子类时会调用一次父类的析构函数
而再调用text1时,因为形参为对象p,因此传值是会临时实例化对象p,函数调用完后这个临时对象p会被销毁,这里jim
和jame
是分别调用Person
的对象和Soldier
的对象的结果
②实参为对象引用(调用text2)
③实参为对象指针(调用text3)
int main(void)
{
Person p;
Soldier s;
text3(&p);
text3(&s);
system("pause");
return 0;
}
可见用引用和指针的方式都不会产生临时对象,更为高效。