继承

来源:互联网 发布: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~

1 0