面向对象的三大特性:封装 继承 多态
继承又分为: 单继承 多继承 虚拟继承 菱形继承
继承存在的意义?
答:继承的存在是为了实现代码复用,以及实现多态。
content:
1. 继承概念
2. 继承关系&访问限定符
3. 派生类的6个默认成员函数
4. 赋值兼容规则
5. 单继承&多继承&菱形继承
1. 继承概念
继承又分为: 单继承 多继承 虚拟继承 菱形继承
继承存在的意义?
答:继承的存在是为了实现代码复用,以及实现多态。
格式:
2. 继承关系&访问限定符
继承后的访问权限:
3. 派生类的6个默认成员函数
构造函数,析构函数,拷贝构造函数,const修饰的取地址操作符重载,取地址操作符重载,赋值运算符重载。
继承关系中的调用顺序:
1.0 当基类的构造函数有形参时,派生类的构造函数必须显式给出,因为构造派生类对象时会先构造基类对象, 而编译器不知道在派生类的初始化列表中调基类的构造函数时具体传什么参数。
2.0 基类没有定义构造函数,则派生类也可以不用定义,全部使用缺省构造函数。
这是因为构造派生类对象时会先构造基类对象,而编译器在派生类的初始化列表里合成了一个缺省的构 造函数。
3.0 基类没有缺省构造函数,派生类必须要在初始化列表中显式给出基类名和参数列表。
实例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Base
{
public:
Base(int b)
{
cout << "Base()" << endl;
}
protected:
};
class Derive : public Base
{
public:
Derive(int b) :Base(b)
{
cout << "Derive()" << endl;
}
protected:
};
继承体系中的作用域
1.0 { }为作用域的起始和结束标志。所以基类和派生类是两个不同的作用域。
2.0 同义隐藏: 基类和派生类有同名函数,子类的函数会屏蔽掉基类的同名函数。
4.赋值兼容规则(public继承)
1.0 派生类对象可以赋值给基类对象,反之不行。
Base b;
Derived d;
b=d;
2.0 基类对象的引用或指针可以指向派生类,反之不行。
Derive d;
base& b=d;
友元与继承友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员。
友元函数不属于类,即不属于基类,相当于全局函数,不能直接访问类的私有成员和保护成员
继承与静态成员
基类定义了static成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有
一个static成员实例。
实例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
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();
system("pause");
return 0;
}
5. 单继承&多继承&菱形继承&菱形虚拟继承
1.0 单继承:
base------Derived
实例:
#include<iostream>
using namespace std;
class Base
{
public:
void SetValue(int pri, int pro, int pub)
{
_pri = pri;
_pro = pro;
}
public:
int _pri;
int _pro;
};
class Derived :public Base
{
public:
void SetValue(int pri, int pro)
{
_pri=pri;
_pro = pro;
}
public:
int _priD;
};
int main()
{
Derived d;
d.SetValue(10,20);
d._priD = 30;
system("pause");
return 0;
}
2.0 多继承
base1 ----Derived,base2-----Derived
实例:
#include<iostream>
using namespace std;
class Base1
{
public:
void SetValue(int pri)
{
_pri = pri;
}
public:
int _pri;
};
class Base2
{
public:
void SetValue(int pro)
{
_pro = pro;
}
public:
int _pro;
};
class Derived :public Base1,public Base2
{
public:
void SetValue(int pri, int pro)
{
_pri=pri;
_pro = pro;
}
public:
int _priD;
};
int main()
{
Derived d;
d.SetValue(10,20);
d._priD = 30;
system("pause");
return 0;
}
3.0菱形继承
实例:
#include<iostream>
using namespace std;
class Base
{
public:
void FunTest1(){}
public:
int _p1;
};
class C1:public Base
{
public:
void FunTest2(){}
public:
int _p2;
};
class C2:public Base
{
public:
void FunTest3(){}
public:
int _p3;
};
class D :public C1, public C2
{
public:
void FunTest3(){}
public:
int _p4;
};
int main()
{
D d;
d.C1::_p1 = 1;
d._p2 = 2;
d.C2::_p1 = 3;
d._p3 = 4;
d._p4 = 5;
system("pause");
return 0;
}
4.0菱形虚拟继承
在菱形继承中有一个问题,基类中的成员变量,在C1和C2里都有一份,在实例化D后改变Base的成员变量说不清改变的是C1里的基类成员变量还是C2里的。所以有了菱形虚拟继承,Base只在D中保留一份。
实例:
#include<iostream>
using namespace std;
class Base
{
public:
void FunTest1(){}
public:
int _p1;
};
class C1 : virtual public Base
{
public:
void FunTest2(){}
public:
int _p2;
};
class C2 :virtual public Base
{
public:
void FunTest3(){}
public:
int _p3;
};
class D :public C1, public C2
{
public:
void FunTest3(){}
public:
int _p4;
};
int main()
{
D d;
d._p1 = 1;
d._p2 = 2;
d._p3 = 3;
d._p4 = 4;
system("pause");
return 0;
}
总结:
继承概念
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持
原有类特性的基础上进行扩展,增加功能。这样产生新的类,称派生类。继承呈现了面向对象程序设
计的层次结构,体现了由简单到复杂的认知过程。
1. 基类的 private 成员在派生类中是不能被访问的,如果基类成员不想在类外直接被访问,但需要
在派生类中能访问,就定义为 protected 。可以看出保护成员限定符是因继承才出现的。
2. public继承是一个接口继承,保持is-a原则,每个父类可用的成员对子类也可用,因为每个子类
对象也都是一个父类对象。
3. protected/private继承是一个实现继承,基类的部分成员并非完全成为子类接口的一部分,
是 has-a 的关系原则,所以非特殊情况下不会使用这两种继承关系,在绝大多数的场景下使用
的都是公有继承。私有继承意味着is-implemented-in-terms-of(是根据……实现的)。通常
比组合(composition)更低级,但当一个派生类需要访问基类保护成员或需要重定义基类的虚
函数时它就是合理的。
4. 不管是哪种继承方式,在派生类内部都可以访问基类的公有成员和保护成员,基类的私有成员存
在但是在子类中不可见(不能访问)。
5. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最
好显示的写出继承方式。
6. 在实际运用中一般使用都是public继承,极少场景下才会使用protetced/private继承.
【说明】
1、基类没有缺省构造函数,派生类必须要在初始化列表中显式给出基类名和参数列表。
2、基类没有定义构造函数,则派生类也可以不用定义,全部使用缺省构造函数。
3、基类定义了带有形参表构造函数,派生类就一定定义构造函数。
继承体系中的作用域
1. 在继承体系中基类和派生类是两个不同作用域。
2. 子类和父类中有同名成员,子类成员将屏蔽父类对成员的直接访问。(在子类成员函数中,可以
使用 基类::基类成员 访问)--隐藏 --重定义
3. 注意在实际中在继承体系里面最好不要定义同名的成员。
继承与转换--赋值兼容规则--public继承
1. 子类对象可以赋值给父类对象(切割/切片)
2. 父类对象不能赋值给子类对象
3. 父类的指针/引用可以指向子类对象
4. 子类的指针/引用不能指向父类对象(可以通过强制类型转换完成)
友元与继承
友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员。
继承与静态成员
基类定义了static成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有
一个static成员实例