目录
一.子类和父类对象的赋值转换
子类对象赋值父类对象的另外两种方式:
总结:
二.父类与子类的作用域
1. 在继承体系中基类和派生类都有独立的作用域。
例:
2.作用域练习
练习1:
解决方法:
一.子类和父类对象的赋值转换
先来看一个案例:变量间的赋值
int main(){
int a;
double b = 10.22;
a = b; //赋值转换
return 0;
}
在上面这个代码中,有两个变量a,b,这两个变量类型分别为整型和浮点型,而变量b赋值给变量a,变量b的值10.22在赋值给变量a的过程中,产生一个临时变量,10.22拷贝一份给了临时变量,在这个临时变量中进行类型转换,10.22-->10,然后临时变量的值10再赋值给变量a。
学习了继承的特性后,我们将通过这个案例看看子类和父类对象的赋值转换过程:
class Person {
public:
void Print() {
cout << "Person类对象的成员属性:" << endl;
cout << _age << endl;
cout << _name << endl;
cout << _hight << endl;
cout << _address << endl;
cout << endl;
}
public:
int _age;
string _name;
int _hight;
string _address="TaiYuan";
};
class Student:public Person{
public:
int _className;
string _grade;
};
int main(){
Person p1;
p1._name = "小曹";
p1._age = 21;
p1._hight = 172;
p1.Print();
Student s1;
s1._name = "小王";
s1._age = 22;
s1._hight = 170;
s1._grade = "大三";
//将子类对象的成员值复制给父类对象
p1 = s1;
}
此时p1对象的成员值就是s1的成员值,但p1并不会有Student子类所创_grade,_className成员变量值,在赋值操作中,子类对象只会将它继承过来的成员值重新赋回给父类对象!!!
这就是子类对象对父类对象的赋值转换——支持向上转换,不支持向下转换。
也就是说父类对象不能赋值给子类对象,因为父类对象中并没有子类对象的_classname、_grade成员值,那它就不能赋!!!
子类对象赋值父类对象的另外两种方式:
创建子类对象并将其成员初始化,而父类对象是采用引用的方式进行向上转换
运行结果:
运行结果:
总结:
子类对象可以赋值给父类的对象、赋给基类的指针、赋给基类的引用。这里有个形象的说法叫“切片”或者“切割”。寓意子类将从父类中继承过来的的那部分成员值切下来赋值给父类对象/指针/引用过去。
二.父类与子类的作用域
1. 在继承体系中基类和派生类都有独立的作用域。
例:
class Person {
public:
void Print() {
cout << "父类的Print函数:" << endl;
cout << "姓名:" << _name << endl;
cout << "年龄:" << _age << endl;
cout << "性别:" << _sex << endl;
cout << endl;
}
int Add(int age=100) {
return _age = ++age;
}
public:
int _age=26;
string _name="王丽";
string _sex="女";
};
class Student :public Person {
public:
void Print() {
cout << "子类的Print函数:" << endl;
cout << "学号:" << _id << endl;
cout << "性别:" << _sex << endl;
cout << "班级:" << _ClassName << endl;
cout << endl;
}
public:
int _id=202001;
string _ClassName="优秀2班";
string _sex="男";
};
int main() {
Person p;
p.Print();
Student s1;
s1.Print();
s1._age = s1.Add();
cout << "对象s1的成员变量_age值为:"<<s1._age << endl;
s1.Person::Print();
return 0;
}
代码解析:从上图代码中可知,父类和子类都各有一个Print()成员函数,而且子类对象和父类对象都调用了Print()函数。
运行结果:
从结果我们发现:子类对象和父类对象调用Print()函数时,都调用的是自家类中的Print(),并没有发生子类调用父类Print()函数的情况。
那么就可以从中得出一个规律:当在父类和子类中都有同名的函数,且这俩类对象都执行调用这个同名函数时,编译器会优先调用该对象自家类中的同名函数,若该类对象中没有该名称的函数,编译器就会从子类继承过父类中的成员函数中寻找该名称函数。
想到这是不是有一点点熟悉感,这不就是变量赋值的情况吗?编译器局部优先法,局部没有就去全局找。
测试代码:
以上就是编译器对子类对象调用函数的详细步骤。
那么又有新的问题了,子类对象就是想调用父类中的Print()函数怎么办?
一般的方式是行不通的,毕竟子类中的Print()摆在那里,而且对于父类子类的同名函数有个“隐藏”机制,子类会将父类继承过来的成员函数做隐藏操作,也就是说表面上子类只存在一个Print函数,虽然子类有父类的Print,但是被子类给藏起来了,不到万不得已不会用。
若就是想调用父类的Print(),就得在调用前加作用域限定符!
所以隐藏只针对于父类子类都各有一个相同名称的成员函数!!!
2.作用域练习
练习1:
class Person {
public:
void Func() {
cout << "Func():" << endl;
cout << endl;
}
public:
int _a;
string _b;
};
class Student :public Person {
public:
void Func(int i) {
cout << "Func(int i)->:" << endl;
}
public:
int _id;
double _result;
};
int main() {
Student s2;
s2.Func();
请问执行代码时会发生什么?
A:造成重载 B:造成重写 C:隐藏/重定义 D:编译出错
习题解析:
如上代码可知:Person类的Func函数是无参函数,而子类Student类的Func函数是带参函数
基于此,若s2.Func();编译器默认会优先调用子类本类的Func函数,但是调用时发现,子类的Func函数需要参数带入,而对象s2调用时,并没有传入实参,所以结果:是选C和D:既会发生隐藏情况,又有编译出错。
总结描述:s2调用的Func()未传参数,导致编译器找不到符合无参的Func函数,报了编译错误,且在此情况中,子类隐藏了从父类继承来的Func()带参函数,也就是说s2想调用的就是从父类继承来的成员函数,但被子类隐藏了,也就调不成,进而出现编译错误。、
解决方法:
//解决方法1:
s2.Person::Func();
//解决方法2:
s2.Func(10);