类和对象 —— 多态

一、多态概念

        多态,通俗来讲就是多种形态。多态分为编译时多态(静态多态)和运⾏时多态(动态多态)。静态多态主要就是函数重载和函数模板,他们传不同类型的参数就可以调⽤不同的函数,通过参数不同达到多种形态,之所以叫编译时多态,是因为他们实参传给形参的参数匹配是在编译时完成的,我们把编译时⼀般归为静态,运行时归为动态。

        而运行时多态,通俗来讲就是一个行为(函数),当传递不同的对象时会进行不同的操作。就比如买票时,普通人买时全价,学生买是半价,军人则是优先买票。同样是买票的行为,不同的人对应的操作却不一样,这就是运行时多态。

二、多态的定义及实现

(1)构成条件

        多态是⼀个继承关系的下的类对象,去调⽤同⼀函数,产⽣了不同的⾏为。⽐如Student继承了Person。Person对象买票全价,Student对象优惠买票。

(2)实现条件

        1、必须是指针或者引用调用虚函数

        2、被调用的函数必须是虚函数

说明:要实现多态效果,第⼀必须是基类的指针或引⽤,因为只有基类的指针或引⽤才能既指向派⽣类对象;第⼆派⽣类必须对基类的虚函数重写/覆盖,重写或者覆盖了,派⽣类才能有不同的函数,多态的不同形态效果才能达到。

        虚函数的定义

        那什么是虚函数呢?在类成员函数前加关键字virtual,该成员函数就称为虚函数,注意,非类成员函数不能加virtual修饰。

class Person
{
public:
    virtual void BuyTicket() { cout << "买票-全价" << endl;}
};
        虚函数的重写

        虚函数的重写/覆盖:派⽣类中有⼀个跟基类完全相同的虚函数(即派⽣类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),称派⽣类的虚函数重写了基类的虚函数。这样才能根据不同的对象执行不同的行为。

class Person {
public:
virtual void BuyTicket() { cout << "买票-全价" << endl; }
};
class Student : public Person {
public:
virtual void BuyTicket() { cout << "买票-打折" << endl; }
};

在重写基类虚函数时,派⽣类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承
后基类的虚函数被继承下来了在派⽣类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使⽤。        

        完整代码:

class Person {
public:
    virtual void BuyTicket() { cout << "买票-全价" << endl; }
};

class Student : public Person {
public:
    virtual void BuyTicket() { cout << "买票-打折" << endl; }
};

void Func(Person* ptr)//这里是基类的指针调用虚函数
{
    // 这⾥可以看到虽然都是Person指针Ptr在调⽤BuyTicket
    // 但是跟ptr没关系,⽽是由ptr指向的对象决定的。
    ptr->BuyTicket();
}

int main()
{
    Person ps;
    Student st;
    Func(&ps);
    Func(&st);
    return 0;
}

此时运行结果就为:买票—全价(换行)买票——打折        

其他问题

        关于虚函数的重写,还有一点需要注意的是基类的析构函数最好也写成虚函数。这样不管子类的析构是否加virtual,都构成重写。虽然两个类的析构函数名称好像不太一样,但是经过编译器统一处理后,析构函数名称统一编程destructor,构成重写。

        下⾯的代码我们可以看到,如果~A(),不加virtual,那么delete p2时只调⽤的A的析构函数,没有调⽤B的析构函数,就会导致内存泄漏问题,因为~B()中在释放资源。

class A
{
public:
    virtual ~A()
    {
    cout << "~A()" << endl;
    }
};

class B : public A {
public:
    ~B()
    {
        cout << "~B()->delete:"<<_p<< endl;
        delete _p;
    }
protected:
    int* _p = new int[10];
};
// 只有派⽣类Student的析构函数重写了Person的析构函数,下⾯的delete对象调⽤析构函数,才能
构成多态,才能保证p1和p2指向的对象正确的调⽤析构函数。
int main()
{
    A* p1 = new A;
    A* p2 = new B;
    delete p1;
    delete p2;
    return 0;
}

三、纯虚函数和抽象类

        在虚函数的后⾯写上 =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()
{
// 编译报错:error C2259: “Car”: ⽆法实例化抽象类
Car car;
Car* pBenz = new Benz;
pBenz->Drive();
Car* pBMW = new BMW;
pBMW->Drive();
return 0;
}

              

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值