继承性是面向对象程序设计最重要的特征,可以说,不掌握继承就不等于掌握类和对象的精华,所以说继承是C++中很重要的一部分。
通过继承,我们可以用原来的数据类型来定义一个新的数据类型,定义的新类型既有原来数据中的成员,也能自己添加新的成员
我们一般把原来的数据类型称为基类或者父类,新的数据类型为派生类,或者子类,在本篇博客中Base为基类,Deriver为派生类
#include
using namespace std;
class Base
{
public:
int i = 1;
};
class Derive:public Base
{
public:
int b = 2;
};
int main()
{
Derive d1;
cout << sizeof(d1) << endl;
return 0;
}
单继承的指向图:
在继承中箭头所指向的地方是有派生类指向基类;
在单继承中,定义的格式:
class 派生类名:继承方式 基类名
{
派生类成员
};
在继承中继承方式有3中,刚刚上面只写了一个public的共有继承;
● public 表示公有继承
● private 表示私有继承
● protected 表示保护继承
class Base1
{
public:
int a = 1;
};
class Base2
{
public:
int b = 2;
};
class Derive:public Base1, public Base2
{
int c = 3;
};
在继承中箭头所指向的地方是有派生类指向基类;
在多继承中,定义的格式:
class 派生类名:继承方式 基类名,继承方式 基类名
{
派生类成员;
};
派生类的组成一般就两部分,一部分是从基类继承过来的,第二部分是自己特有的;
所以在单继承中我的示意图Derive比Base的图大点,有存放自己特色的空间;
主要注意的是多继承中空间的分布:
在多继承中靠派生类近的基类属于先声明的,所以数据在派生类中最先被保存;
所以说,在多继承中,派生类的数据模型和继承顺序有很大关系
我们在前面学类的时候就知道:public,protected,private的访问权限
访问方式 | 类里面 | 类外面 |
---|---|---|
public | 允许访问 | 允许访问 |
protected | 允许访问 | 不允许访问 |
private | 允许访问 | 不允许访问 |
这三种访问权限,在继承方式后也有所改变了
class Base
{
public:
Base(int a = 0, int b = 0, int c = 0)
: _pub(a)
, _pro(b)
, _pri(c)
{}
int _pub = 1;
protected:
int _pro = 2;
private:
int _pri = 3;
};
class Derive :public Base
{
public:
void display()
{
cout << "_pub" << _pub << endl;
cout << "_pro" << _pro << endl;
cout << "_pri" << _pri << endl;
}
};
在public继承中,派生类访问基类的private成员时就会报错:
class Base
{
public:
Base(int a = 0, int b = 0, int c = 0)
: _pub(a)
, _pro(b)
, _pri(c)
{}
int _pub = 1;
protected:
int _pro = 2;
private:
int _pri = 3;
};
class Derive :protected Base
{
public:
void display()
{
_pro = 10;
}
};
int main()
{
Derive d1;
d1._pub = 4;
d1._pro = 5;
d1._pri = 6;
return 0;
}
在protected继承中在派生类中可以访问基类中的protected成员,但是在main函数中_pub和_pro都不能被访问了;
如果你想要成员能在函数内部被访问,在函数外面不能被访问就用protected继承,可以说protected就是为继承而生的
class Base
{
public:
Base(int a = 0, int b = 0, int c = 0)
: _pub(a)
, _pro(b)
, _pri(c)
{}
int _pub = 1;
protected:
int _pro = 2;
private:
int _pri = 3;
};
class Derive :private Base
{
public:
void display()
{
_pub = 20;
_pro = 10;
_pri = 30;
}
};
int main()
{
Derive d1;
d1._pub = 4;
d1._pro = 5;
d1._pri = 6;
return 0;
}
在私有继承中,从基类继承下来的东西全部就变为了派生类私有的,所以你在外部完全访问不了,或许有人认为在外部访问不了和protected继承好像没什么区别,你从再次创建一个派生类来访问它的protected成员时是可以访问的,但是private成员就访问不了;
继承方式 | 基类的public成员 | 基类的protected成员 | 基类的private成员 | 继承引起的访问控制关系变化概括 |
---|---|---|---|---|
public继承 | 仍为public成员 | 仍为protected成员 | 不可见 | 基类的非私有长远在子类的访问属性不变 |
protected继承 | 变为protected成员 | 变为protected成员 | 不可见 | 基类的非私有成员都为子类的保护成员 |
private继承 | 变为private成员 | 变为private成员 | 不可见 | 基类中的非私有成员都称为子类的私有成员 |
在继承中不管是单继承还是多继承,都要注明继承方式,如果不注明在class中默认为private继承,在struct中默认public继承
在类的学习中,我们都了解了友元,友元可以访问指定类的私有和受保护的自定义成员,如果不是指定的成员,则不能被访问
友元类
(1) 友元函数不是类成员函数,所以不能被继承;
(2) 友元关系是单向的,不具有交换性;
若B类是A类的友元,不一定A类就是B类的友元
(3) 友元关系不能被传递,若B类是A类的友元,C类是B类的友元,C类不一定是A类的友元
友元注意事项
a、友元函数可访问类的私有成员,但不是类的成员函数;
b、友元函数不能用const修饰;
c、友元函数可以在类定义的任何地方声明,不受类访问限定
符限制;
d、一个函数可以是多个类的友元函数;
e、友元函数的调用与普通函数的调用和原理相同;
f、友元关系不能继承,基类的友元对派生类的成员没有特殊的访问权限。如果基类被授予友元关系,则只有基类具有特殊的访问权限。该基类的派生类不能访问授予友元关系的类。
class Base
{
friend void fun();
public:
Base(int a = 0, int b = 0, int c = 0)
: _pub(a)
, _pro(b)
, _pri(c)
{}
int _pub = 1;
protected:
int _pro = 2;
private:
int _pri = 3;
};
class Derive :public Base
{};
int main()
{
Derive d1;
d1.fun();
return 0;
}
fun函数不是派生类的成员函数,说明friend函数不能被继承
class Person
{
public:
Person(){ ++_count; }
protected:
string _name; // 姓名
public:
static int _count; // 统计人的个数。
};
int Person::_count = 0;
class Student : public Person
{
protected:
int _stuNum; // 学号
};
class Graduate :public Student
{
protected:
string _seminarCourse; // 研究科目
};
void TestPerson1()
{
Student s1;
Student s2;
Student s3;
Graduate s4;
cout << "人数:" << Person::_count << endl;
Student::_count = 0;
cout << "人数:" << Person::_count << endl;
}
int main()
{
TestPerson1();
return 0;
}
在这段代码和结果中。我们可以看到的是_count是可以被继承下来的,并且在整个继承体系中static成员只有一个,无论有多少个派生类,都只仅仅有一个static成员;