一、继承
//1.类中的保护和私有在当前类中没有差别;
//2.在继承后的子类中有差别,private在子类中不可见,所以用protected;
class person
{
public:void print(){cout << "name:" << _name << endl;cout << "age:" << _age << endl;}
protected: //若换为private,则执行错误string _name = "peter";int _age = 18;
};class student: public person
{
protected:int stuid;
};
int main()
{student s;s.print();return 0;
}
二、 基类和派生类对象赋值转换
class person
{
protected:string _name;string _sex;int _age;
};
class student: public person
{
protected:int stuid;
};
int main()
{person p;student s;//子类和父类之间的赋值兼容规则//1.子类对象可以赋值给父类对象/指针/引用p = s;person* ptr = &s;person& ref = s;//反过来s = p; //不可以student* ptr = &p; //有时候可以student& ref = p;return 0;
}
指针ptr指向student类中父类的那一部分;
引用ref是子类student中父类那一部分的别名;
三、继承中的作用域
class person
{
protected:string _name = "peter";int _num = 111;
};
class student: public person
{
public:void print(){cout << "姓名:" << _name << endl;cout << "学号:" << _num << endl;}
protected:int _num = 999;
};
int main()
{student s;s.print(); return 0;
}
//输出: 姓名:peter// 学号:999
//1.两个_num在不同的作用域中,一个在父类,一个在子类,不会报错;
//2.当父类和子类同时有同名成员时,子类的成员隐藏于父类的成员(重定义);
//优先访问子类,现在子类中找,再去父类;
访问父类_num:
class person
{
protected:string _name = "peter";int _num = 111;
};
class student: public person
{
public:void print(){cout << "姓名:" << _name << endl;cout << "学号:" << _num << endl;cout << "学号:" << person::_num << endl; //指定作用域即可}
protected:int _num = 999;
};
int main()
{student s;s.print();return 0;
}
//1.A和B的fun构成什么关系?
//重定义(隐藏),不是重载,重载必须在同一个作用域
//函数只要函数名相同,不需要参数相同
class A
{
public:void fun(){cout << "func()" << endl;}
};
class B : public A
{
public:void fun(int i){A::fun();cout << "func(int i)->" << i << endl;}
};int main()
{B b;b.fun(); //执行错误b.fun(123456);b.A::fun(); //调用A的fun()return 0;
}
四、派生类的默认成员函数
class Person
{
public://1.构造函数Person(const char* name = "peter"): _name(name){cout << "Person()" << endl;}//2.拷贝构造Person(const Person& p): _name(p._name){cout << "Person(const Person& p)" << endl;}//3.赋值Person& operator=(const Person& p){cout << "Person operator=(const Person& p)" << endl;if (this != &p)_name = p._name;return *this;}//4.析构函数~Person(){cout << "~Person()" << endl;}
protected:string _name;
};class Student : public Person
{
public:Student(const char* name, int num): Person(name) //调用父类的构造函数, _num(num){cout << "Student()" << endl;}Student(const Student& s): Person(s) //调用父类的拷贝构造, _num(s._num){cout << "Student(const Student& s)" << endl;}Student& operator=(const Student& s){if (this != &s){Person::operator =(s);//重定义,调用父类的person::_num = s._num;}cout << "Student& operator= (const Student& s)" << endl;return *this;}~Student() {// Person::~Person();//与~Person()构成隐藏cout << "~Student()" << endl;//调用子类析构后会自动调用父类析构}
protected:int _num; //学号
};
int main()
{Student s1("peter",11);Student s2(s1);return 0;
}
//输出:
Person() //父类构造
Student() //子类构造
Person(const Person& p) //父类拷贝构造
Student(const Student& s) //子类拷贝构造
~Student() //s2析构
~Person() //子类调用析构,自动调用父类析构
~Student() //s1析构
~Person()
int main()
{Student s1("peter",11);Student s3("rose",20);s1 = s3;return 0;
}
//输出:
Person() //s1构造
Student()
Person() //s2构造
Student()
Person operator=(const Person& p) //父类赋值
Student& operator= (const Student& s) //子类赋值
~Student() //s3析构
~Person()
~Student() //s1析构
~Person()
如何设计一个不能被继承的类?
构造函数私有化,不能被继承,对象无法生成
class A
{
private:A(){}
};
class B :public A
{};
五、友元与继承
友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员
class Student; //注意
class Person
{
public:friend void Display(const Person& p, const Student& s);
protected:string _name;
};
class Student : public Person
{friend void Display(const Person& p, const Student& s);
protected:int _stuNum;
};void Display(const Person& p, const Student& s)
{cout << p._name << endl;cout << s._stuNum << endl;
}
int main()
{Person p;Student s;Display(p, s);return 0;
}
或者:
class Student;
class Person
{
protected:string _name;
};
class Student : public Person
{friend void Display(const Person& p, const Student& s);
protected:int _stuNum;
};void Display(const Person& p, const Student& s)
{cout << s._name << endl;cout << s._stuNum << endl;
}
int main()
{Person p;Student s;Display(p, s);return 0;
}
六、继承与静态成员
基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例 。
class Person
{
public:Person() { ++_count; }string _name; static int _count;
};
int Person::_count = 0;
class Student : public Person
{
public:int _stuNum;
};
int main()
{Person p;Student s;p._name = "jack";s._name = "rose";p._count = 1;s._count = 2;cout << Person::_count << endl;return 0;
}
_count放在静态区,只有一个_count,p和s中的_count是一个
七、复杂的菱形继承及菱形虚拟继承
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";
}
解决方法:
class Person
{
public:string _name; // 姓名
};
class Student : virtual public Person
{
protected:int _num; //学号
};
class Teacher : virtual public Person
{
protected:int _id; // 职工编号
};
virual分析:
八、继承和组合
//1.public继承是一种is-a的关系。也就是说每个派生类对象都是一个基类对象。//2.组合是一种has-a的关系。假设B组合了A,每个B对象中都有一个A对象。//3.继承与组合都可以的情况下,优先使用对象组合,而不是类继承 。
// Car和BMW Car和Benz构成is-a的关系
class Car {
protected:string _colour = "白色"; // 颜色string _num = "陕ABIT00"; // 车牌号
};class BMW : public Car {
public:void Drive() { cout << "好开-操控" << endl; }
};class Benz : public Car {
public:void Drive() { cout << "好坐-舒适" << endl; }
};
// Tire和Car构成has-a的关系
class Tire {
protected:string _brand = "Michelin"; // 品牌size_t _size = 17; // 尺寸
};
class Car {
protected:string _colour = "白色"; // 颜色string _num = "陕ABIT00"; // 车牌号Tire _t; // 轮胎
};