目录
一、多态的概念
顾名思义,多态就是多种形态,举个例子:比如说买票这个行为,当普通人买票时是全价票,学生买票时是半价票,军人买票时是优先买票。也就是说一件事,每个不同的类去做,会发生不一样的行为称之为多态。
二、多态的定义及实现
1、多态的构成条件
1、多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。比如 Student 继承了Person。 Person 对象买票全价, Student 对象买票半价。 2、必须通过基类的指针或者引用调用虚函数。 3、被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写。
2、虚函数
虚函数就是被virtual修饰的类成员函数成为虚函数。
class Person{
public:
virtual void BuyTicket()
{
cout << "全价票" << endl;
}
}
3、虚函数的重写
当派生类中和基类有一个完全相同的虚函数。派生类和基类都得写才标准。class Person {
public:
virtual void BuyTicket()
{
cout << "买票-全价" << endl;
}
};
class Student : public Person {
public:
virtual void BuyTicket()
{
cout << "买票-半价" << endl;
}
//void BuyTicket() { cout << "买票-半价" << endl}
};
void Func(Person& p)
{
p.BuyTicket();
}
int main()
{
Person ps;
Func(ps);
Student st;
Func(st);
return 0;
}
3.1、协变:
派生类重写基类虚函数时,与基类虚函数返回的类型不同。
3.2、析构函数重写:
如果基类的析构函数是虚函数,那么派生类的析构函数默认会和基类的析构函数构成重写,虽然函数名不同,但是编译器进行编译后,把析构函数统一处理为destructor。
class Person
{
public:
virtual void BuyTicket()
{
cout << "全价" << endl;
}
virtual Person* F()
{
return new Person;
}
virtual ~Person()
{
cout << "~Person" << endl;
}
};
class Student : public Person
{
public:
virtual void BuyTicket()
{
cout << "半价" << endl;
}
virtual Student* F()
{
return new Student;
}
virtual ~Student()
{
cout << "~Student" << endl;
}
};
void Test(Person& p)
{
p.BuyTicket();
}
int main()
{
Person p;
Student s;
Test(p);
Test(s);
return 0;
}析构了两次~Person
class Person {
public:
~Person()
{
cout << "~Person()" << endl;
}
};
class Student : public Person {
public:
~Student()
{
cout << "~Student()" << endl;
}
};
int main()
{
Person* p1 = new Person;
Person* p2 = new Student;
delete p1;
delete p2;
return 0;
}
为什么会调用两次~Person()? 而且没有调用~Student()。子类的指针赋给父类指针时,会发生切割。p2 指针只会指向属于父类的那一部分,子类的析构函数自然也就没有赋值过去。所以调用的是父类的析构函数, 并不能正确的释放掉动态开辟的空间。只有派生类 Student 的析构函数重写了 Person 的析构函数,下面的 delete 对象调用析构函数,才能构成多态,才能保证 p1 和 p2 指向的对象正确的调用析构函数。
修改后:
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;
}
4、override 和 final 关键字
C++11中, 用来辅助进行虚函数多态的多种复杂情况,避免出现疏忽而导致错误的情况出现。
override : 检查派生类虚函数是否重写了基类的某个虚函数,如果没有就会报错。
class Person
{
public:
/*virtual*/ void BuyTicket()
{
cout << "全价票" << endl;
}
};
class Student : public Person
{
public:
virtual void BuyTicket() override//报错
{
cout << "半价票" << endl;
}
};
class Child : public Student
{
public:
virtual void BuyTicket() override
{
cout << "半价票" << endl;
}
};
final : 修饰虚函数,表示这个虚函数不能被重写。
class Person
{
public:
virtual void BuyTicket()
{
cout << "全价票" << endl;
}
};
class Student : public Person
{
public:
virtual void BuyTicket() final
{
cout << "半价票" << endl;
}
};
class Child : public Student
{
public:
virtual void BuyTicket()//
{
cout << "半价票" << endl;
}
};
5、重载、覆盖、隐藏
1.重载指的是,函数名在一个作用域,并且函数名相同,参数不同的情况,那么这两个函数就构成了函数重载,编译器在进行处理的时候会根据参数形成不同的函数表。
2.重写指的是,两个函数在基类和派生类的作用域下,前提是函数名、参数、返回值都一样的情况下,如果是虚函数,那么就构成了重写,其中子类可以不写virtual,可以理解为虚函数的属性被从基类中继承了下来,但是并不推荐这样写,其中要注意特殊情况,比如协变和析构函数的情况。
3.隐藏指的是,两个函数在基类和派生类的作用域下,当函数名相同的时候,如果不符合重写的定义那么就是重定义了,比如在继承中见到的很多种情况。
三、抽象类
抽象类的定义:在虚函数后面写上=0,就是纯虚函数,有纯虚函数的类就是抽象类,特点是不能实例化出一个具体的对象派生类也是不能,只有在重写了虚函数,才能实例化,纯虚函数体现了派生类要重写的这个原则,同时也体现了接口继承的概念。
基类 - 抽象类 - 不能实例化出对象
class Car
{
public:
virtual void Drive() = 0; 纯虚函数,不需要实现它
};
派生类
class Benz :public Car
{
public:
virtual void Drive() 必须重写基类虚函数,派生类才能实例化出对象
{
cout << "Benz-舒适" << endl;
}
};
class BMW :public Car
{
public:
virtual void Drive()
{
cout << "BMW-操控" << endl;
}
};
int main()
{
基类是抽象类,不能实例化出对象,但可以定义基类指针,用来实现多态
Car* pBenz = new Benz;
pBenz->Drive();
Car* pBMW = new BMW;
pBMW->Drive();
return 0;
}
1、接口继承
接口继承(Interface Inheritance)是指从一个纯虚基类(pure virtual base class)继承而来,目的是为了实现一个类的接口,使得派生类必须实现该接口中定义的所有纯虚函数。接口继承的主要目的是实现类的接口复用,它并不关心实现细节。在接口继承中,派生类只需要实现基类中定义的纯虚函数,不需要关心基类中其他的数据和函数。
class Shape
{
public:
virtual void draw() = 0;//纯虚函数
};
class Cirrle : public Shape
{
public:
void draw() override
{
//实现圆形的绘画
}
};
class Squre : public Shape
{
void draw() override
{
//实现矩形的绘画
}
};
2、实现继承
实现继承(Implementation Inheritance)是指从一个普通的基类(非纯虚基类)继承而来,目的是为了实现基类中已有的函数或数据。实现继承的主要目的是实现代码复用,它关心基类中的实现细节。在实现继承中,派生类会继承基类中所有的成员函数和数据成员,并且可以重写这些函数以改变它们的行为。
class Person
{
public:
virtual void Say()
{
cout << "Person" << endl;
}
};
class Student : public Person
{
public:
virtual void Say() override
{
cout << "Student" << endl;
}
};
int main()
{
Person p;
Student s;
s.Say();
return 0;
}
下章节介绍多态的原理!如有不正之处,希望大家私信我去改正!
标签:函数,基类,多态,C++,class,派生类,重写,public From: https://blog.csdn.net/2201_75956982/article/details/143978352