继承的基础语法
当我们写类的时候,如果每个类都有相同的部分,那么通过一个个将其中的内容一个个敲出来将会十分占空间,那么我们就会用到继承
方法:将公共的内容专门写出一个类出来,然后写别的子类时候,加入公共部分即可。
语法:class 子类:继承方式 父类
(其中子类又叫做派生类,父类叫做基类)
下面看例子:
#include <iostream> #include <string> using namespace std; //这里是公共的部分,也就是下面子类都共有的部分,先写出来 class BasePage { public: void head() { cout<<"上部的内容:........"<<endl; } void foot() { cout<<"下部的内容:........"<<endl; } void left() { cout<<"左边的内容:........"<<endl; } }; //子类c++ class Cpp:public BasePage //这里就可以将公共的部分添加至类中,减少重复内容 { public: void cpp1() { cout<<"c++的内容"<<endl; } }; class Py:public BasePage //这里同样也是 { public: void py1() { cout<<"python的内容"<<endl; } }; void test() { //分别输出对应的自己有的内容和公共的内容 Cpp c; c.head(); c.foot(); c.left(); c.cpp1(); cout<<"---------"<<endl; Py py; py.foot(); py.head(); py.left(); py.py1(); } int main() { test(); system("pause"); return 0; }
运行程序:
好处:可以减少很多在子类中重复的内容
———————————————————————————————————
继承方式
公共继承 保护继承 私有继承
若子类公共继承父类,那么除了父类的私有属性访问不到其余与父类对应继承
若子类保护继承父类,那么除了父类的私有属性访问不到其余都为保护继承
若子类私有继承父类,那么除了父类的私有属性访问不到其余都为私有继承
注意在类外,对于类的保护属性以及私有属性都不能访问及修改,公共属性可以访问及修改
例子:
#include <iostream> #include <string> using namespace std; class father { public: int a; protected: int b; private: int c; }; //公共继承 class son1:public father { public: void func() { a = 100; //此时a为公共继承 b = 100; //b为保护继承 //c = 100; //c访问不到 } }; void test01() { son1 s; s.a = 100; //是公共属性可以访问到 //s.b =200; //类外访问不到保护属性 } //保护继承 class son2:protected father { public: void func() { a = 100; //此时a为保护继承 b = 100; //b为保护继承 //c = 100; //c访问不到 } }; void test02() { son2 s; //s.a = 100; //类外访问不到a //s.b =200; //类外访问不到b } //私有继承 class son3:private father { public: void func() { a = 100; //此时a为保护继承 b = 100; //b为保护继承 //c = 100; //c访问不到 } }; void test03() { son3 s; //s.a = 100; //类外访问不到a,因为是私有属性 //s.b =200; //类外访问不到b,因为是私有属性 } int main() { test01(); system("pause"); return 0; }
———————————————————————————————————
父类中的所有非静态成员属性都会被子类继承下去
父类中私有成员属性也会被继承下去,只不过是被编译器隐藏了
子类继承父类时,构造函数与析构函数的顺序?
答:当子类继承父类的时候,先调用父类构造函数,再调用子类构造函数,析构函数与其相反
———————————————————————————————————
继承同名的成员关系
1.子类对象可以直接访问到子类中同名成员
2.子类对象加作用域可以访问到父类同名成员
3.当子类与父类拥有同名的成员函数,子类会隐藏掉父类中同名的成员函数,加作用域可以访问到父类的成员函数
例子:
#include <iostream> #include <string> using namespace std; //父类 class father { public: father() { a = 100; } void func() { cout<<"父类进行调用"<<endl; } void func(int a) { cout<<"a = "<<a<<endl; } int a; }; //子类进行公共继承父类 class son:public father { public: son() { a = 200; } void func() { cout<<"子类进行调用"<<endl; } int a; }; //子类父类同名成员属性时候 void test() { son s1; cout<<"son中的a:"<<s1.a<<endl; //直接访问,就可以访问到子类的成员属性 cout<<"father中的a:"<<s1.father::a<<endl; //加一个作用域就可以访问到父类的成员属性 } //同名成员函数 void test01() { son s1; s1.func();//直接进行调用子类中的同名函数 //当父类与子类拥有同样名字的成员函数,编译器会自动隐藏掉父类的成员函数, s1.father::func(100); //加上作用域才能访问父类的成员函数,不能直接调用s1.func(100) } int main() { test01(); system("pause"); return 0; }
———————————————————————————————————
访问同名静态成员,与非静态相似
例子:
#include <iostream> #include <string> using namespace std; //定义一个父类 class Base { public: static void func() { cout<<"父类的void func()进行调用"<<endl; } static void func(int a) { cout<<"父类的static void func(int a)调用"<<endl; } static int a; }; int Base::a = 100; //定义一个子类 class son:public Base { public: //静态成员函数 static void func() { cout<<"子类的void func()进行调用"<<endl; } static int a; //类内静态变量初始化 }; int son::a = 200; //访问静态成员属性 void test01() { //1.通过对象访问静态成员属性 cout<<"通过对象访问静态成员函数"<<endl; son s1; cout<<"son下的静态成员属性"<<s1.a<<endl; //直接访问类内成员 cout<<"Base下的静态成员属性"<<s1.Base::a<<endl; //访问子类时要加作用域 //2.通过类名来访问 cout<<"通过类名访问静态成员函数"<<endl; cout<<"son下的静态成员属性"<<son::a<<endl; //直接访问类内成员 cout<<"Base下的静态成员属性"<<Base::a<<endl; //访问子类时要加作用域 } //访问静态成员函数 void test02() { //通过对象访问 cout<<"通过对象访问"<<endl; son s1; //s1.func(100); //若子类成员函数与父类相同时,会隐藏父类的同名成员函数,需要加作用域才能访问 s1.Base::func(100); s1.func(); s1.Base::func(); //2.通过类名访问 cout<<"通过类名访问"<<endl; son::func(); Base::func(); } int main() { test02(); system("pause"); return 0; }
———————————————————————————————————
多继承语法:class 子类:继承方式 父类1,继承方式 父类2 {};
例子:
#include <iostream> #include <string> using namespace std; class Base1 //父类1 { public: Base1() { m_a = 100; //设一个同名m_a } int m_a; }; class Base2 //父类2 { public: Base2() { m_a = 200; } int m_a; }; class son:public Base1,public Base2 //继承两个父类 { public: son() { m_a = 400; d = 300; } int m_a; int d; }; void test() { son s; cout<<"sizeof(s):"<<sizeof(s)<<endl; cout<<"子类下的m_a = "<<s.m_a<<endl; //直接访问 cout<<"Base1下的m_a = "<<s.Base1::m_a<<endl; //加作用域 cout<<"Base2下的m_a = "<<s.Base2::m_a<<endl; //加作用域 //总结:多继承下访问父类继承下来同名要加作用域 } int main() { test(); system("pause"); return 0; }
总结:多继承下访问父类继承下来同名要加作用域
———————————————————————————————————
菱形继承
形成条件:
1.两个派生类继承一个基类
2.一个类再继承两个派生类
这个就叫做菱形继承,也叫做钻石继承
问题:此时这个类便产生了两义性
解决:
1.在继承之前加virtual,此时父类又称为虚基类
2.此时可以直接访问这个类的成员属性
例子:
#include <iostream> #include <string> using namespace std; class animal { public: int m_age; }; class sheep:virtual public animal {}; //下面两个派生类继承一个基类 class tuo:virtual public animal {}; class sheeptuo:public sheep,public tuo {};//一个类再继承两个派生类,此时便有了二义性,有两个m_age void test01() { sheeptuo st; st.sheep::m_age = 18; st.tuo::m_age = 15; //哪个最后更改数值,就为哪个,并且两个继承类的属性都会更改 cout<<"羊的年龄为:"<<st.sheep::m_age<<endl; cout<<"驼的年龄为:"<<st.tuo::m_age<<endl; cout<<"羊驼的年龄为:"<<st.m_age<<endl; //继承之前加上virtual 便可以直接进行访问 } int main() { test01(); system("pause"); return 0; }
运行程序:三个年龄都为15,是按照最后赋值的结果来进行指向的。
时间:2020.1.14-15