一、组合
组合在好久之前就接触了,只是不知道运用的就是组合罢了。是的直白点组合就是将已有类的对象作为另一个类的成员,通过成员对象使用已有类的功能。就稍微写个代码提示一下吧!
class Engine{....};
class Wheel{.....};
class Car
{
Engine a;
Wheel wheel[4];
};
注意:
1.一般作为新类的私有成员。
2.作为新类的对象时,如果想对已有类进行操作,需要通过已有类中的操作函数进行。
知识点:
(一)成员对象的初始化问题
当已有类成员作为新类的成员时,可以通过显式初始化和系统自动调用已有类的默认初始化函数这两种方式进行。一般来说每个类中都会有构造函数,所以一般都是通过后者进行初始化,这里就写一下显式初始化吧!
class Member
{
int x;
public:
Member(int a):x(a){}
};
class Withmember
{
int y;
Member m;
public:
Withmember(int a,int b):m(a),y(b){}
};
(二)指针成员与聚合关系
聚合关系的特点就是成员对象可以独立于聚合对象存在,聚合对象被创建或撤销时,成员对象可以不受影响。可以通过按指针组合的方式实现。
class Coach{....};
class Player{....};
class Team
{
Coach* coach;
vector<Player*>players;
public:
Team(Coach* pc)
{
coach=pc;
}
void changecoach(Coach* pnc)
{
coach=pnc;
}
void employplayer(Player* player)
{
players.push_back(player);
}
void fireplayer(Player* player)
{
//通过迭代器找到指定球员it
if(it!=players.end())
{
players.erase(it);
}
}
};
二、继承
C++中被继承的称之为基类,继承得到的称之为派生类,派生类可以被再次继承,这样构成的层次结构就是继承层次。派生类中含有基类的所有内容(析构与构造函数除外)。
语法形式如下;
class 派生类名字:访问限定符 基类名字
{成员声明}
继承分为三种:公有继承(public),私有继承(private),保护继承(protected)。一般情况下使用公有继承。
知识点:
- 一个类的public成员在任何类与函数中都是可以访问的,private成员只有在本类与本类的友元可以访问,protected成员的权限在其他两个之间,在派生类中可以访问。所以在基类中的数据成员一般会设置为protected,或者在设置为私有数据后,可以在基类中中提供操作函数(public或protected),间接对基类的私有数据进行操作,以方便使用。
- 在公有派生类中,在基类中的成员是什么类型,那么他在派生类就是什么类型;在私有派生类中,基类的所有成员在派生类中都成为私有成员;在保护派生类中,基类中的在派生类中成为保护成员。(以上的继承规则仅是对基类的非私有成员而言,基类的私有成员无论是什么派生类都是不可见的)
- 改变个别成员的可访问性
可以通过使用using声明,对派生类中继承的基类成员进行可见性调整。
class a{...};
class c:(public|private|protected) a
{
(public|private|protected):
using a::成员名;
};
- 禁止继承的类
在禁止继承的类名后面加关键字final
class a final{…}; - 静态成员的继承:
基类中的static成员,则在整个继承层次中该成员唯一,但是如果在基类中是private成员,则在所有的派生类中都无权访问。 - 覆盖与同名隐藏
在派生类中重新定义基类中的同名成员后,基类中的名字在派生类中被隐藏。
(1) 在派生类中重新定义基类中的成员函数后,参数表与返回类型保持与基类中的一致,这种称之为覆盖。
(2) 如果参数表与返回类型不一致,则是隐藏。 - 虚基类
在继承时,将基类的声明为虚基类,语法为:
class 派生类名:virtual 访问限定符 基类名{…};
class 派生类名: 访问限定符 virtual 基类名{…};
代码如下:
class A{...};
class B:virtual public A{...};
class C:virtual public A{...};
class D:public B,public C{...};
这样D类仅仅继承了一个A,不会多次。
8.继承后的新类函数初始化
class A
{
protected:
int a,b;
public:
A(int c=1,int d=2):a(c),b(d){}
};
class B:public A
{
int e;
public:
B(int a=1,int b=2,int c=3):A(a,b),e(c){}
};
三、虚函数与多态性
一般情况下,函数是通过静态绑定的,在派生类向基类转化的过程中会产生切片现象,即使通过引用和指针的方式也会损失信息。在调用相同的函数时,只会调用基类的函数,而不会自行调整调用派生类的函数。只有通过动态绑定方式才可以完美的执行理想的操作。声明虚函数与声明虚基类差不多都是加关键字virtual。语法:
virtual 返回类型 成员函数名(参数表);
(1) 在派生类中覆盖基类的虚函数时要用相同的参数表和返回类型。
(2) 可以通过使用关键字override来标记派生类中的虚函数,只有这样编译器才会检查出错误。
实现多态的步骤:
- 在基类中将需要多态调用的成员函数声明为virtual;
- 在派生类中覆盖基类中的虚函数,实现各自的需要的功能;
- 用基类的引用或者指针指向派生类的对象,通过基类的指针或者引用调用虚函数。
class A
{
public:
virtual void moneys(){}
};
class B:public A
{
public:
void moneys()override{}
};
class C:public A
{
void moneys()override{}
};
void outmoneys(A& c)
{
c.moneys();
}
int main()
{
B a;
outmoneys(a);
C c;
outmoneys(c);
}