发布于2024-11-02 10:33 阅读(555) 评论(0) 点赞(8) 收藏(3)
目录
在前面我们对C++的封装,继承等特性都有了了解和学习,接下来我们将对C++的第三大特性-多态进行认识和掌握。内容分为来两大部分,第一个是对多态的认识和运用,第二大部分是对多态原理的了解和扩展。
多态(Polymorphism)是面向对象编程(OOP)中的一个核心概念,它指的是同一个行为具有多个不同表现形式或形态的能力。在编程中,多态通常通过继承(inheritance)和接(interfaces来实现。
以下是多态的几个主要方面:
编译时多态(静态多态):这是在编译时确定的多态性,通常通过函数重载(function overloading)和模板(templates)来实现。编译器根据函数的参数类型或数量来决定调用哪个函数。
运行时多态(动态多态):这是在程序运行时确定的多态性,主要通过虚函数(virtual functions)和继承来实现。在运行时,根据对象的实际类型来调用相应的成员函数。
多态的关键特性包括:
- #define _CRT_SECURE_NO_WARNINGS
- #include <iostream>
- 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();
- }
- //指针调用
- void func1(Person* p) {
- p->BuyTicket();
- // 这⾥可以看到虽然都是Person指针Ptr在调⽤BuyTicket
- // 但是跟ptr没关系,⽽是由ptr指向的对象决定的。
- }
- int main() {
- Person p1;
- Student s1;
- Person* p2 = new Person();
- Student* s2 = new Student();
- func(p1);
- func(s1);
- p1.BuyTicket();
- s1.BuyTicket();
- func1(&p1);
- func1(&s1);
- p2->BuyTicket();
- s2->BuyTicket();
-
- return 0;
- }
void func(Student& p) {
p.BuyTicket();
}
//指针调用
void func1(Student* p) {
p->BuyTicket();
}
如果改成Student,就会出问题,就不是多态了,也就不能传Person对象了。
- #include <iostream>
- using namespace std;
-
- class Pet {
- public:
- virtual void eat() const{
- cout << "Eat food" << endl;
- }
- };
- class Dog : public Pet{
- public:
- virtual void eat() const {
- cout << "Dog eats meat!" << endl;
- }
- };
- class Cat :public Pet {
- public:
- virtual void eat()const {
- cout << "Cat eats fish!" << endl;
- }
- };
- void func(const Pet& p) {
- p.eat();
- }
- int main() {
- Pet p;
- Dog g;
- Cat c;
- func(p);
- func(g);
- func(c);
- return 0;
- }
上述是宠物的一个多态实现。
这里我们测试一下,基类函数不加virtual会怎样,
class Pet {
public:
void eat() const{
cout << "Eat food" << endl;
}
};
我们会发现多态效果没有实现,所以一定要加上virtual.
下面程序输出结果是什么?(B)
class A {public:virtual void func(int val = 1){ std::cout<<"A->"<< val <<std::endl;}virtual void test(){ func();}};class B : public A {public:void func(int val = 0){ std::cout<<"B->"<< val <<std::endl; }};int main(int argc ,char* argv[]) {B*p = new B;p->test();return 0; }
B* p = new B;
创建了一个 B
类型的对象,并通过基类指针 p
指向它。p->test();
调用了 A
类的 test
方法(因为 B
类没有重写 test
方法)。A
类的 test
方法中,func(val)
被调用,没有指定 val
的值,因此它使用 A
类 func
方法的默认参数 1
。func
是虚函数,并且 p
指向一个 B
类型的对象,所以 B
类的 func
方法被调用,接收到的参数是 1
。- #define _CRT_SECURE_NO_WARNINGS
- #include <iostream>
- using namespace std;
-
- class A {};
- class B : public A {};
- class Person {
- public:
- virtual A* BuyTicket()
- {
- cout << "买票-全价" << endl;
- return nullptr;
- }
- };
- class Student : public Person {
- public:
- virtual B* BuyTicket()
- {
- cout << "买票-打折" << endl;
- return nullptr;
- }
- };
- void Func(Person* ptr)
- {
- ptr->BuyTicket();
- }
- int main()
- {
- Person ps;
- Student st;
- Func(&ps);
- Func(&st);
- return 0;
- }
故在C++中,当一个基类的析构函数被声明为虚函数时,它确保了当通过基类指针或引用删除派生类对象时,会调用正确的析构函数,即派生类的析构函数,然后再调用基类的析构函数。这是因为虚析构函数允许动态绑定,确保了派生类对象被正确地销毁。
- #include <iostream>
- using namespace std;
- class A {
- public:
- virtual ~A() {
- cout << "delete A" << endl;
- }
- };
- class B :public A {
- public:
- ~B() {
- cout << "~B()->delete:" << _p << endl;
- delete _p;
- }
- protected:
- int* _p = new int[10];
- };
- int main() {
- A* a = new A;
- A* b = new B;
- delete a;
- delete b;
- return 0;
- }
当我们不把基类析构函数设置成virtual时, 会发现没有调用B的析构,该释放的资源没有释放掉。
- public:
- ~A() {
- cout << "delete A" << endl;
- }
- };
故基类的析构函数我们要设置成虚函数。
-
- class Car {
- public:
- virtual void Dirve()
- {}
- };
- class Benz :public Car {
- public:
- virtual void Drive() override { cout << "Benz-舒适" << endl; }
- };
比如上面这个例子,函数名写错了,重写失败,编译报错。
final 关键字用于防止类被进一步派生,或者防止虚函数被重写。当应用于类时,它表示这个类不能被继承。当应用于虚函数时,它表示这个虚函数不能在派生类中被重写。
- class Car {
- public:
- virtual void Dirve() final
- {}
- };
- class Benz :public Car {
- public:
- virtual void Dirve(){ cout << "Benz-舒适" << endl; }
- };
class Base final { // 不能从这个类派生其他类
public:
virtual void doSomething() const final {} // 这个虚函数不能被重写
};
// 下面的类声明会导致编译错误,因为 Base 是 final 的
// class Derived : public Base {};
// 下面的函数声明也会导致编译错误,因为 doSomething 是 final 的
// class Derived : public Base {
// public:
// void doSomething() const override {} // 错误:不能重写 final 函数
// };
使用 final 关键字可以确保类或虚函数的行为不会被意外的继承或重写改变,这对于设计那些不打算被扩展的类或函数非常有用。
重载(Overloading)
重写(Overriding)
override
关键字可以明确指出重写意图。隐藏(Hiding)
- #include <iostream>
- using namespace std;
- class Car {
- public:
- virtual void Drive() = 0;
-
- };
- class Benchi :public Car {
- public:
- virtual void Drive() {
- cout << "Benchi-舒适" << endl;
- }
- };
-
- class Baoma :public Car {
- public:
- virtual void Drive() {
- cout << "Baoma-上手" << endl;
- }
- };
- int main() {
- Car car;
- Car* b = new Benchi();
- b->Drive();
- Car* m = new Baoma();
- m->Drive();
- return 0;
- }
这里Car是抽象类,所以无法实例化对象。
本期内容就到此结束了,内容有点多,下节我们将对多态的原理进行补充讲解。
最后感谢各位友友的支持!!!
原文链接:https://blog.csdn.net/2302_79376097/article/details/143300145
作者:咿呀咿呀哟
链接:http://www.javaheidong.com/blog/article/691560/c12dc3d5d45a7f56290a/
来源:java黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!