继承
导航:
1.继承的基础语法
2.继承的方式(成员属性及成员函数)
3.子类继承父类时,构造函数及析构函数的顺序
4.继承同名的成员关系,如何访问
5.访问同名静态成员
6.多继承语法
7.菱形继承
———————————————————————————————————
继承的基础语法
当我们写类的时候,如果每个类都有相同的部分,那么通过一个个将其中的内容一个个敲出来将会十分占空间,那么我们就会用到继承
方法:将公共的内容专门写出一个类出来,然后写别的子类时候,加入公共部分即可。
语法: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