如有兴趣了解更多请关注我的个人博客https://07xiaohei.com/
(一)概念:
继承机制是面向对象程序设计中最重要的一个概念,也是使代码可以复用的最重要的手段。
继承机制允许我们依据一个类来定义另一个类,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,能使对类的创建和维护更加容易——能够重用代码功能和提高执行效率。
被继承的类,也就是已有的类,被称为基类(父类),而发生继承的类,也就是新建的类,被称为派生类(子类)。
如果要使用基类的成员,派生类不需要重新编写新的数据成员和成员函数,只需要指定继承的已有的类的成员。但是,派生类不能继承基类的构造函数、析构函数、拷贝构造函数、重载运算符和友元函数。
一个基类可以派生出多个派生类,一个派生类也可以从多个基类中继承数据成员和成员函数。
派生类只能访问基类的非私有成员。
(二)继承的语法形式:
class 派生类名:基类名表
{
数据成员和成员函数声明
};
其中,基类和一般情况下声明的类基本相同。
基类名表的组成为:
访问控制 基类名1 , 访问控制 基类名2 , …
访问控制是关键字,表示派生类对基类的继承方式。
#include<iostream>
using namespace std;
class person
{
};
class animal
{
};
class knowledge{};
class student :public animal,protected person,private knowledge
{
};
class teacher:public animal, protected person, private knowledge
{
};
(三)继承的三种方式:
访问控制的关键字共有三个,分别为public、private和protected。
如果未直接指定访问控制关键字,默认为private。
访问控制决定了不同的访问权限和访问类型,详细情况见下表。
可以看到,对于基类成员,派生类的继承如下:
- 基类的私有成员,派生类不可以访问
- 基类的保护成员,派生类可以继承为自己的保护成员(protected继承)和私有成员(private继承),在派生类可以访问,在外部不可以访问。
- 基类的公有成员,子类可以继承为自己的公有成员(public继承),保护成员(protected继承)和私有成员(private继承)。在派生类可以访问,在外部也可以访问。
对于派生类,公有继承保持基类的保护成员和公有成员不变;保护继承将基类的公有和保护成员变为保护成员;私有继承则将公有和保护成员变为私有成员。
注意:通过派生类可以初始化基类的私有数据成员,方式是通过调用基类的构造函数来实现对私有数据成员的初始化。
注意:虽然基类的私有数据成员不能在派生类中直接访问,但是派生类的对象也会为其建立私有的数据空间,所有继承时即使基类数据成员均为私有,也会导致派生类的占用空间很大。
#include<iostream>
using namespace std;
class Axy //基类
{
private:
string Aname;
protected:
double x;
double y;
public:
Axy(double d1 = 0, double d2 = 0,string s = "pointA" ):Aname(s),x(d1),y(d2){ }
double getx() { return x; }
double gety() { return y; }
string getAname() { return Aname; }
};
class Bxy :public Axy //公有继承A,除了不能继承Aname,其余保持不变,构造函数不继承需要重新写
{
private:
string Bname;
public:
//对基类的一种初始化方式
Bxy(double d1 = 0, double d2 = 0, string s1 = "pointB",string s2 ="pointA") :Bname(s1), Axy(d1, d2, s2) {}
};
class Cxy:protected Axy //保护继承A,不能继承Aname,其他均变为protected类型,构造函数不继承需要重新写
{
private:
string Cname;
public:
Cxy(double d1 = 0, double d2 = 0, string s1 = "pointC") :Cname(s1)
{
//继承可以直接使用基类的非私有数据成员
x = d1;
y = d2;
}
void use_A_function()
{
//继承可以使用基类的非私有成员函数
cout << getx() << endl;
cout << gety() << endl;
return;
}
void use_A_function2()
{
cout << x << endl;
cout << y << endl;
return;
}
};
class Dxy:private Cxy //私有继承C,不能继承Cname,其他均变为private类型,构造函数不继承需要重新写
{
private:
string Dname;
public:
Dxy(double d1 = 0, double d2 = 0, string s = "pointD") :Dname(s), Cxy(d1, d2) {}
};
class Exy :public Dxy //保护继承D,因为上面均变为private类型,所以什么都都没继承,只能对其构造和析构
{
private:
string Dname;
public:
Exy(double d1 = 0, double d2 = 0, string s = "pointD") :Dname(s), Dxy(d1, d2) {}
};
int main()
{
Bxy b(1,1,"bbb","aaa");
cout << "b:" << b.getx() << "," << b.gety() << endl; //调用A的成员函数处理B的数据成员
cout << "Aname:" << b.getAname() << endl;
Cxy c; //c为保护继承,类外均不能调用原有的成员函数
c.use_A_function(); //通过调用C的成员函数调用A的成员函数处理C的数据成员
c.use_A_function2(); //调用C的成员函数对C的数据成员操作
Dxy d; //d为私有继承,类外均不能调用原有的成员函数
Exy e; //e为公有继承,但什么都没继承到,所以没有可以调用的成员函数。
cout << sizeof(Axy) << endl;
cout << sizeof(Bxy) << endl;
cout << sizeof(Cxy) << endl;
cout << sizeof(Dxy) << endl;
cout << sizeof(Exy) << endl;
return 0;
}
//运行结果:
//b:1, 1
//Aname : aaa
//0
//0
//0
//0
//56
//96
//96
//136
//176
(四)重名成员:
- 同名也称为隐藏,派生类定义了与基类同名的成员时,派生类的同名成员会屏蔽掉基类的同名成员——子类优先。
- 如果要使用基类的同名成员,需要显式地使用类名限定符。
- 对于成员函数,同名的要求是函数名相同,对参数列表没有要求。
- 注意基类和派生类的作用域是独立的(表现为各有自己的this指针),但是基类的作用域被延伸到了派生类中(也就是在派生类的作用域中可以调用基类的作用域)。
#include<iostream>
using namespace std;
class Axy
{
private:
string Aname;
protected:
double x;
double y;
public:
Axy(double d1 = 0, double d2 = 0,string s = "pointA" ):Aname(s),x(d1),y(d2){ }
double getx() { return x; }
double gety() { return y; }
string getAname() { return Aname; }
};
class Bxy :public Axy
{
private:
string Bname;
protected:
double x;
double y;
public:
Bxy(double d1 = 0, double d2 = 0, double d3=0,double d4=0,string s1 = "pointB",string s2 ="pointA"):x(d1),y(d2),Bname(s1), Axy(d3, d4, s2) {}
double getx() { return x; } //访问默认的子类的同名变量x
double gety() { return y; } //访问默认的子类的同名变量y
double getAx() { return Axy::x; } //访问基类的同名变量x
double getAy() { return Axy::y; } //访问基类的同名变量y
string getAname() { return Axy::getAname(); } //调用基类的成员函数getAname,这里绝对不能不加作用域,否则会陷入死循环。
string getBname() { return Bname; }
};
int main()
{
Bxy b;
cout << "b:" << b.getx() << "," << b.gety() << endl;
cout << "a:" << b.getAx() << "," << b.getAy() << endl;
cout << "a:" << b.Axy::getx() << "," << b.Axy::gety() << endl;
cout << "bname:" << b.getBname() << endl;
cout << "aname:" << b.getAname() << endl;
cout << "aname:" << b.Axy::getAname() << endl;
return 0;
}
//运行结果:
//b:0, 0
//a : 0, 0
//a : 0, 0
//bname : pointB
//aname : pointA
//aname : pointA
(五)派生类访问静态成员:
- 基类定义的静态成员将被所有派生类共享。
- 根据静态成员自身的访问特性和派生类的继承方式,类层次体系中有不同的访问性质。
- 派生类中访问静态成员,用以下形式显式说明:
- 类名::成员
- 对象名.成员
#include<iostream>
using namespace std;
class A
{
public:
static int i;
static void add_i()
{
i++;
return;
}
void print() { cout << "i:" << i << endl; }
};
int A::i = 0;
class B:protected A
{
public:
void add_i2()
{
i++;
return;
}
};
int main()
{
A a;
B b;
a.i++;
a.add_i();
b.add_i2();
//b.A::add_i(); protect继承不能在类外访问A的成员
//B::A::add_i(); 这样也不行
A::i++;
A::add_i();
a.print();
return 0;
}
//运行结果:
//i:5