目录
- 一.继承&复用&组合的区别
- 二.继承的基本格式与继承以后的访问方式变化(基类成员)
- 三.基类和派生类对象赋值转换【切片概念】
- 四.继承中的【隐藏】
- 五.派生类的默认成员函数生成机制
- 六.“友元关系”不能被继承
- 七.基类定义了static静态成员,整个继承体系里面只有一个这样的成员
- 八.复杂的菱形继承及菱形虚拟继承
一.继承&复用&组合的区别
1)函数复用与继承区别
2)复用的分类
[1]白箱复用——继承
[2]黑箱复用——组合(优先)
二.继承的基本格式与继承以后的访问方式变化(基类成员)
1)基本格式
2)三种继承方式
3)在派生类中不可见
4)基类成员经过不同继承以后分别到派生类的什么作用域中【访问方式变化】
5)struct和class的默认继承方式
6)实际运用中一般使用都是public继承的原因
三.基类和派生类对象赋值转换【切片概念】
class Person
{
protected :
string _name; // 姓名
string _sex; // 性别
int _age; // 年龄
};
class Student : public Person
{
public :
int _No ; // 学号
};
void Test ()
{
Student sobj ;
// 1.子类对象可以赋值给父类对象/指针/引用
Person pobj = sobj ;
Person* pp = &sobj;
Person& rp = sobj;
//2.基类对象不能赋值给派生类对象
sobj = pobj;
// 3.基类的指针可以通过强制类型转换赋值给派生类的指针
pp = &sobj
Student* ps1 = (Student*)pp; // 这种情况转换时可以的。
ps1->_No = 10;
pp = &pobj;
Student* ps2 = (Student*)pp; // 这种情况转换时虽然可以,但是会存在越界访问的问题
ps2->_No = 10;
}
四.继承中的【隐藏】
五.派生类的默认成员函数生成机制
六.“友元关系”不能被继承
//fail
class Student;
class Person
{
public:
friend void Display(const Person& p, const Student& s);
protected:
string _name; // 姓名
};
class Student : public Person
{
protected:
int _stuNum; // 学号
};
void Display(const Person& p, const Student& s)
{
cout << p._name << endl;
cout << s._stuNum << endl;
}
void main()
{
Person p;
Student s;
Display(p, s);
}
七.基类定义了static静态成员,整个继承体系里面只有一个这样的成员
class Person
{
public :
Person () {++ _count ;} //派生类会调用基类的构造
protected :
string _name ; // 姓名
public :
static int _count; // 统计人的个数。
};
int Person :: _count = 0;
class Student : public Person
{
protected :
int _stuNum ; // 学号
};
class Graduate : public Student
{
protected :
string _seminarCourse ; // 研究科目
};
void TestPerson()
{
Student s1 ;
Student s2 ;
Student s3 ;
Graduate s4 ;
cout <<" 人数 :"<< Person ::_count << endl; //输出结果为4
Student ::_count = 0;
cout <<" 人数 :"<< Person ::_count << endl; //输出结果为0
}
八.复杂的菱形继承及菱形虚拟继承
1)菱形继承
class Person
{
public :
string _name ; // 姓名
};
class Student : public Person
{
protected :
int _num ; //学号
};
class Teacher : public Person
{
protected :
int _id ; // 职工编号
};
class Assistant : public Student, public Teacher
{
protected :
string _majorCourse ; // 主修课程
};
void Test ()
{
// 这样会有二义性无法明确知道访问的是哪一个
Assistant a ;
a._name = "peter";
// 需要显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决
a.Student::_name = "xxx";
a.Teacher::_name = "yyy";
}
2)解决菱形继承问题方法:虚拟继承
class Person
{
public :
string _name ; // 姓名
};
class Student : virtual public Person //虚拟继承
{
protected :
int _num ; //学号
};
class Teacher : virtual public Person //虚拟继承
{
protected :
int _id ; // 职工编号
};
class Assistant : public Student, public Teacher
{
protected :
string _majorCourse ; // 主修课程
};
void Test ()
{
Assistant a ;
a._name = "peter";
}