继承
来源:互联网 发布:mac打字不出现选择框 编辑:程序博客网 时间:2024/06/05 05:42
本篇博客,来给大家讲一下C++中的继承,包括继承的概念,继承关系和继承下的访问限定符,以及相关实例解释。1.什么是继承?继承是面向对象复用的重要手段,继承是类型之间的关系建模,共享共有的东西,实现各自本质不同的东西。继承是一种复用手段,在继承类里基类继承派生类的成员,由此达到复用的目的。
2.访问限定符
public (公有) protected (保护) private (私有)
3.三种继承关系下基类成员的派生类访问关系变化:
public继承:基类的非私有成员在子类里的访问属性不变都不变
protected继承:基类的非私有成员都成为子类的保护成员
private继承:基类中的非私有成员都成为子类的私有成员
无论哪种继承方式,基类的私有成员都是不可见的。
4.总结
(1)基类的私有成员在派生类中是不能被访问的,如果一些基类成员不想被基类对象直接访问,但需要在派生类中能访问,就定义为保护成员,可以看出保护成员限定符是因继承才出现的。
(2)public继承是一个接口继承,保持is-a的关系原则,每个父类可用的成员对子类也可用,因为每个子类对象也都是一个父类对象。
(3)protected/private继承是一个实现继承,基类部分成员并未完全成为子类接口的一部分,是has-a的关系原则,所以非特殊情况下不会使用这两种继承关系,在绝大多数的场景下使用的都是公有继承。
(4)不管是哪种继承方式,在派生类内部都可以访问基类的公有成员和保护成员。
(5)使用关键字class时默认继承方式是private,使用struct时默认继承方式是pubic,最好写出继承方式。
(6)在实际运用中一般都是使用public继承,极少场景下才会使用private/protected继承。
5.继承与转换—赋值兼容规则—public继承
(1)子类对象可以赋值给父类对象,但父类对象不可以赋值给子类对象
(2)父类的指针/引用可以指向子类对象,子类的指针/引用不可以指向父类对象(可以通过强制类型转换完成)
#include <iostream>using namespace std;class A //基类 父类{public: int _a;};class B :public A//派生类 子类 (继承了父类public A){public: int _b;}; //运行结果解释见下面图一int main(){ A aa; aa._a = 1; B bb; bb._a = 2; bb._b = 3; aa = bb; system("pause"); return 0;}//运行结果及解释见图二int main(){ A aa; aa._a = 1; B bb; bb._a = 2; bb._b = 3; //aa = bb;//子类对象可以给父类对象 //A* p = &bb; //父类对象指针可以指向子类对象 A& r = bb;//父类对象可以是子类对象的别名 //指针引用语法在实际运行底层都创建了指针变量 r._a = 10; aa = bb; system("pause"); return 0;}
运行结果图一:
图二:
6.子类对象可以赋给父类对象(切割/切片)
7.隐藏 (重定义)
继承体系中的作用域:在继承体系中基类和派生类都有独立的作用域。
子类、父类同名成员(函数/变量),子类会隐藏父类同名成员。
子类和父类中有同名成员,子类将屏蔽父类对成员的直接访问。(在子类成员函数中,可以使用基类::基类成员 访问) —隐藏 —重定义;
注意在实际中继承体系里面最好不要定义同名的成员 。
#include <iostream>using namespace std;class AA{public: int f(int a) { cout<<"AA::f()"<<endl; return 0; } int a;};class BB : public AA{public: void f(double a) { cout<<"BB::f()"<<endl; } int a; int b;};// 隐藏int main(){ BB bb; bb.a = 10; bb.AA::a = 20; bb.f(1); //bb.AA::f(1); return 0;}
8.类的六个默认成员函数:构造函数,析构函数,拷贝构造函数,赋值运算符重载函数,取地址操作符重载,const修饰的取地址操作符重载
派生类的默认成员函数
在继承关系里面,在派生类中如果没有显示定义这六个默认成员函数,编译系统则会默认合成这六个默认成员函数。
#include <iostream>#include <string>using namespace std;class Person{public: Person(char* name = "小黑")//类对象成员初始化 :_name(name) { cout << "Person()" << endl; } Person(const Person& p)//拷贝构造函数 :_name(p._name) { cout << "Person(const Person& p)" << endl; } Person& operator=(const Person& p)// 赋值操作符重载 { cout << "Person& operator=(const Person& p)" << endl; if (this != &p) { _name = p._name; } return *this; } ~Person()//析构函数 { cout << "~Person()" << endl; }protected: string _name;};class Student : public Person{public: Student(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); _num = s._num; } cout << "Student& operator=(const Student& s)" << endl; return *this; } ~Student()//析构函数 { cout << "~Student()" << endl; }protected: int _num; // 学号};void test1(){ Person p; Student s("Mary", 17);}int main(){ test1(); system("pause"); return 0;}
好了,今天继承相关的知识就讲到这里,继承多态里面有很多知识点,有时容易混淆,慢慢地去理解,你会发现代码有时也是很好玩的,之后的相关知识我会继续分享的,Bye~