C++面向对象的三大特征(四大特征)
三大特征:封装、继承、多态
四大特征:抽象、封装、继承、多态
一、类和对象
类是数据类型,是具有相同属性和服务的一组对象的集合。对一类对象的抽象就是类。
对象即观察研究对象,是类这种数据类型创建出的实例(相当于结构变量)。
类与对象的区别:
1、类是一个抽象的概念,类只是为所有的对象定义了抽象的属性和行为;对象是类的一个具体,是实体。
2、类是静态概念,本身不携带任何数据;对象是动态概念,每个对象都有自己独特的属性和行为,且它的属性可以随着行为而发生改变。
注意:C++中类和结构的区别只有成员函数和成员变量默认访问权限不同。
二、类的继承
1、一个子类可以同时继承多个父类,每个父类的继承方式可以相同也可以不同。
class 子类:继承方式 父类,...{}
2、继承的基本特点:
- 子类会继承父类的所有成员,但不能访问父类中的私有成员
- 子类的指针或引用可以隐式转换成父类的指针或引用
- 子类会隐藏父类的同名成员
1、可通过域限定符进行访问
2、可以使用父类的指针或引用来指向子类对象
3、继承方式影响访问控制
①访问控制限定符
注意:private子类需要调用父类的成员函数来访问
友元与内部的区别,友元需要类的指针或引用
- 总结:
public成员在类内、子类中、外部都可以随意访问
private成员只能在类中才能访问,外部不能访问
protected成员在类内和子类中都可以访问,即只能被类内或子类访问,但不能被子类的对象访问(属于外部)
②继承方式
- 总结:
C++中的继承方式有public、private、protected三种(它们直接影响到子类的成员及其对象对父类成员访问的规则)
public(公有继承):父类中各成员属性不变,且父类中private成员被隐藏;子类成员只能访问父类中的public、protected成员;子类对象只能访问父类的public成员
private(私有继承):父类中各成员属性均变为private,且父类中private成员被隐藏;子类成员只能访问父类中的public、protected成员;子类对象不能访问父类的任何成员
protected(保护继承):父类中各成员属性均变为protected,且父类中private成员被隐藏;子类成员只能访问父类中的public、protected成员;子类对象不能访问父类的任何成员
4、子类的构造、析构、拷贝
构造函数:先(根据继承表顺序)执行父类的构造函数→执行子类的构造函数
(默认执行父类的无参构造)
析构函数:先执行子类析构→(根据继承表逆顺序)执行父类的析构函数
拷贝构造:当使用子类对象来初始化新的子类对象时,会自动调用子类缺省的拷贝构造函数,并且会先调用父类缺省的拷贝构造函数。
三、虚函数、覆盖、多态
1、虚函数:类的成员函数前加virtual
2、覆盖:子类会覆盖父类的虚函数
3、多态:当子类覆盖了父类的虚函数时,通过父类指针指向子类对象时,调用虚函数,会根据具体的对象是谁来决定执行谁的函数。
-
覆盖的条件
1、父类中的成员函数必须是虚函数
2、必须是父子类之间(不同作用域)
3、函数名相同,参数列表完全一致
4、返回值必须是同类或父子类
5、const属性也会影响覆盖结果
-
隐藏的条件
1、子类与父类的函数完全相同,且父类函数不是虚函数,此时父类函数会被隐藏
2、子类和父类函数同名,参数列表不同,此时父类函数会被隐藏
-
多态的条件
1、父子类之间有覆盖关系的函数
2、父类的指针或引用指向子类对象
-
函数重载的条件
1、在同一作用域下
2、函数名必须相同
3、参数列表不同
-
构造函数和析构函数能否是虚函数
1、构造函数不能是虚函数,析构函数可以是虚函数。
2、当使用delete释放一个父类指针时不管指向的对象是谁都只会调用父类的析构函数,此时若子类中有资源还未释放就会造成内存泄漏,因此在多态条件下,需要把父类的析构函数设置为虚函数(析构函数在进行覆盖时不会比较函数名),当父类的析构为虚函数时,通过父类指针或引用释放子类对象时,会自动调用子类的析构函数,而子类的析构函数执行完成后会自动调用父类的析构函数,从而避免内存泄漏。
实现类的工厂模式
工厂模式:在创建对象时通过一个共同的接口来指向新创建的对象。
#include <iostream>
using namespace std;
enum ClassType{typeA,typeB,typeC,typeD};
class Base
{
public:
virtual void whoami(void)=0;//设置纯虚函数用来约束子类
};
class A:public Base
{
void whoami(void)
{
cout<<"A"<<endl;
}
};
class B:public Base
{
void whoami(void)
{
cout<<"B"<<endl;
}
};
class C:public Base
{
void whoami(void)
{
cout<<"C"<<endl;
}
};
class D:public Base
{
void whoami(void)
{
cout<<"D"<<endl;
}
};
Base* CreateClass(ClassType type)
{
switch(type)
{
case typeA:return new A;
case typeB:return new B;
case typeC:return new C;
case typeD:return new D;
}
return NULL;
}
int main()
{
Base* b=CreateClass(typeB);
b->whoami();
}