追设计网站,优化的定义,赣州seo唐三,各网站特点目录
1、什么是虚函数
1.1 什么是虚函数重写
1.2 虚函数的继承
1.3 协变
1.4 析构函数的重写
2、override和final
2.1 final
2.2 override
3、纯虚函数/抽象类
3.1 接口继承和实现继承
4、多态的原理 前言#xff1a; 在C中#xff0c;多态指的是调用同一个类的…目录
1、什么是虚函数
1.1 什么是虚函数重写
1.2 虚函数的继承
1.3 协变
1.4 析构函数的重写
2、override和final
2.1 final
2.2 override
3、纯虚函数/抽象类
3.1 接口继承和实现继承
4、多态的原理 前言 在C中多态指的是调用同一个类的成员函数时会产生两种不同的结果因此多态又称多种形态。 实现多态的前提是 1、两个类必须满足继承关系。 2、必须通过基类的指针或引用去调用该类的成员函数并且这个成员函数是被virtual修饰过的虚函数还得完成虚函数的重写。 多态结构示意图如下 1、什么是虚函数 被关键字virtual修饰的类成员函数就是虚函数比如下面的BuyTicket就是一个虚函数。
class Person {
public:virtual void BuyTicket() { cout 买票-全价 endl; }
};
1.1 什么是虚函数重写 在基类和派生类中都存在一个相同的虚函数即函数名、函数形参类型及个数、返回类型都相同这时候把派生类中的虚函数叫做基类虚函数的重写。 注意虚函数重写和虚函数是两个概念即虚函数不一定构成虚函数重写构成虚函数重写的前提是两个函数必须是虚函数。 体现虚函数重写的代码如下
#define _CRT_SECURE_NO_WARNINGS 1#includeiostream
using namespace std;class Person {
public:virtual void BuyTicket() { cout 买票-全价 endl; }
};
class Student : public Person {
public:virtual void BuyTicket() { cout 买票-半价 endl; }
};void Func(Person p)
{ p.BuyTicket();
}
int main()
{Person ps;Student st;Func(ps);Func(st);return 0;
} 运行结果 从结果可以看到虚函数重写的目的就是为了实现多态上面代码通过同一个形参p调用两个不同的函数BuyTicket从而达到实现不同的功能。
1.2 虚函数的继承 在继承关系中派生类可以继承基类的成员那么虚函数也是可以被继承的比如拿上述代码举例Student类中如果没有对BuyTicket函数进行virtual修饰却同样可以实现多态的效果原因就是派生类继承了基类的虚函数virtual让自己的BuyTicket也变成了一个虚函数。 但是如果基类中的BuyTicket函数不是虚函数而派生类的BuyTicket是虚函数则无非满足虚函数的重写。 1.3 协变 从上文可以得知虚函数重写的要求是函数名、函数形参类型及个数、返回类型都相同则协变就是在此基础上放宽了对虚函数重写的要求即返回类型不相同的虚函数也可以构成重写但是返回的必须是指针或者引用并且这两个虚函数的返回值是继承关系。 协变示例代码如下
#define _CRT_SECURE_NO_WARNINGS 1#includeiostream
using namespace std;class Person {
public:virtual Person BuyTicket() { cout 买票-全价 endl; return *this; }
};
class Student : public Person {
public:virtual Student BuyTicket() { cout 买票-半价 endl; return *this;}
};void Func(Person p)
{ p.BuyTicket();
}
int main()
{Person ps;Student st;Func(ps);Func(st);return 0;
} 运行结果 协变示意图如下 1.4 析构函数的重写 析构函数的重写可以不满足协变和虚函数重写的要求只需要对两个类的析构函数加上virtual即可实现重写。原因在于派生类和基类的析构函数都会被统一处理成destructor的函数名这时候他们就满足了虚函数重写的要求此时函数名相同了。
#define _CRT_SECURE_NO_WARNINGS 1#includeiostream
using namespace std;class Person {
public:virtual ~Person() { cout ~Person() endl; }
};
class Student : public Person {
public:virtual ~Student() { cout ~Student() endl; }
};int main()
{Person* p1 new Person;Person* p2 new Student;delete p1;delete p2;return 0;
} 运行结果 2、override和final override和final的目的就是手动的对虚函数重写进行严格的检查因为在实现虚函数重写的时候有些疏忽编译器是不会报错的因此我们可以使用override和final严格要求虚函数的重写。
2.1 final 修饰一个虚函数让其不能被重写。 示例代码
#define _CRT_SECURE_NO_WARNINGS 1#includeiostream
using namespace std;class Person
{
public:virtual void Number() final {}
};
class Student :public Person
{
public:virtual void Number() {}//由于基类在虚函数后面加了final因此此处不能被重写
};int main()
{return 0;
} 运行结果 2.2 override override的作用是检查被修饰的虚函数是否重写了基类的某个虚函数。 override示例代码如下
#define _CRT_SECURE_NO_WARNINGS 1#includeiostream
using namespace std;class Person
{
public://virtual void Number() {}
};
class Student :public Person
{
public://Person类中没有实现Number虚函数因此此处没有实现虚函数的重写virtual void Number()override {}
};int main()
{return 0;
} 报错原因 3、纯虚函数/抽象类 在虚函数的声明末尾处写上“0”则该虚函数为纯虚函数。而这个纯虚函数所在的类称之为抽象类即不能用该类实例化对象并且继承该抽象类的派生类也不能实例化出对象。 纯虚函数/抽象类的写法
#define _CRT_SECURE_NO_WARNINGS 1#includeiostream
using namespace std;class Person
{
public:virtual void Number()0 {}
};
class Student :public Person
{
public://virtual void Number() {}
};int main()
{Person p;Student s;//Person和Student都不能实例化出对象return 0;
} 只有重写了该抽象类中的纯虚函数才能用派生类实例化出对象基类还是不能实例化对象
#define _CRT_SECURE_NO_WARNINGS 1#includeiostream
using namespace std;class Person
{
public:virtual void Number()0 {}
};
class Student :public Person
{
public:virtual void Number() {}//重写纯虚函数
};int main()
{//Person p;//Person依旧不能实例化对象Student s;//由于Student中的Number重写了Person的Number因此Student可以实例化对象return 0;
}
3.1 接口继承和实现继承 实现继承就是我们所说的派生类继承了基类的成员函数继承的是该函数的整体。而接口继承是虚函数继承虚函数继承的只是函数的接口部分并不是整个函数。他们是有区别的。 体现他们区别的示意图如下 4、多态的原理 实现多态的根本原因是虚函数的重写而在底层中在基类部分会自动生成一个数组指针又称虚表指针该指针指向的数组是用来存放虚函数地址的这个生成动作在编译阶段就已经完成了所以该数组又称虚函数表。 因此当调用条件满足多态时编译器实际上会到基类中找到虚表指针然后调用的是该指针指向的虚函数这也是为什么通过同一个接口可以实现两个不同结果。 可以通过观察一个类的大小来发现虚指针的存在
#define _CRT_SECURE_NO_WARNINGS 1#includeiostream
using namespace std;class Person {
public:virtual void BuyTicket() { cout 买票-全价 endl; }
};int main()
{Person ps;cout sizeof(ps) endl;//ps的大小为4return 0;
} 通过监视窗口也可以发现虚表指针的存在 如果是继承关系则虚表指针存放在父类中的基类部分中这也是为什么实现多态的条件之一是需要基类指针调用虚函数因为虚表指针存在基类部分中使用基类指针刚好可以与其对应。 结语 以上就是关于多态的讲解 多态的本质就是继承并且需要满足虚函数重写和基类指针、引用调用多态实际上只需要记住这两点即可只不过在此基础上可以延申出更多的细节。最后希望本文可以给你带来更多的收获如果本文对你起到了帮助希望可以动动小指头帮忙点赞关注收藏如果有遗漏或者有误的地方欢迎大家在评论区补充谢谢大家