C++学习(6)多态

1.虚函数和多态

  • 在类的定义中,前面有virtual关键字的成员函数就是虚函数。
  • virtual关键字只用在类定义里的函数说明中,写函数体时不用。

  • 多态的表现形式一
    派生类的指针可以赋给基类指针。
    通过基类指针调用基类和派生类中的同名虚函数时:
    (1)若该指针指向一个基类的对象,那么被调用是
    基类的虚函数;
    (2)若该指针指向一个派生类的对象,那么被调用
    的是派生类的虚函数。
    这种机制就叫做“多态”。
class CBase {
public:
    virtual void SomeVirtualFunction() { }
};
class CDerived :public CBase {
public:
    virtual void SomeVirtualFunction() { }
};
int main() {
    CDerived ODerived;
    CBase * p = &ODerived;
    p->SomeVirtualFunction(); //调用哪个虚函数取决于p指向哪种类型的对象
    return 0;
}

  • 多态的表现形式二
    派生类的对象可以赋给基类引用
    通过基类引用调用基类和派生类中的同名虚函数时:
    (1)若该引用引用的是一个基类的对象,那么被调
    用是基类的虚函数;
    (2)若该引用引用的是一个派生类的对象,那么被
    调用的是派生类的虚函数。
    这种机制也叫做“多态”。
class CBase {
public:
    virtual void SomeVirtualFunction() { }
};
class CDerived :public CBase {
public:
    virtual void SomeVirtualFunction() { }
};
int main() {
    CDerived ODerived;
    CBase & r = ODerived;
    r.SomeVirtualFunction(); //调用哪个虚函数取决于r引用哪种类型的对象
    return 0;
}

  • 多态的作用
    在面向对象的程序设计中使用多态,能够增强程序的可扩充性,即程序需要修改或增加功能的时候,需要改动和增加的代码较少。

用基类指针数组存放指向各种派生类对象的指针,然后遍历该数组,就能对各个派生类对象做各种操作,是很常用的做法

  • 构造函数和析构函数中调用虚函数
    在构造函数和析构函数中调用虚函数,不是多态。编译时即可确定,调用的函数是自己的类或基类中定义的函数,不会等到运行时才决定调用自己的还是派生类的函数。

2.多态的实现原理

“多态” 的关键在于通过基类指针或引用调用
一个虚函数时,编译时不确定到底调用的是基类还是派生类的函数,运行时才确定 ---- 这叫“动态联编” 。

  • 多态实现的关键 --- 虚函数表
    每一个有虚函数的类(或有虚函数的类的派生类)都有一个虚函数表,该类的任何对象中都放着虚函数表的指针。虚函数表中列出了该类的虚函数地址。 多出来的4个字节就是用来放虚函数表的地址的。


    批注 2020-08-13 221906.png

3.虚析构函数

  • 通过基类的指针删除派生类对象时,通常情况下只调用基类的析构函数
     但是,删除一个派生类的对象时,应该先调用派生类的析构函数,然后调用基类的析构函数。
    解决办法:把基类的析构函数声明为virtual
     派生类的析构函数可以virtual不进行声明
     通过基类的指针删除派生类对象时,首先调用派生类的析构函数,然后调用基类的析构函数
     一般来说,一个类如果定义了虚函数,则应该将析构函数也定义成虚函数。或者,一个类打算作为基类使用,也应该将析构函数定义成虚函数。
    注意: 不允许以虚函数作为构造函数
class son {
public:
    ~son() { cout << "bye from son" << endl; };
};
class grandson :public son {
public:
    ~grandson() { cout << "bye from grandson" << endl; };
};
int main() {
    son *pson;
    pson = new grandson();
    delete pson;
    return 0;
}
//输出: bye from son 没有执行grandson::~grandson()!!!
class son {
public:
    virtual ~son() { cout << "bye from son" << endl; };
};
class grandson :public son {
public:
    ~grandson() { cout << "bye from grandson" << endl; };
};
int main() {
    son *pson;
    pson = new grandson();
    delete pson;
    return 0;
}
//输出: bye from grandson
//bye from son
//执行grandson::~grandson(),引起执行son::~son()!!!

4.纯虚函数和抽象类

 纯虚函数: 没有函数体的虚函数

class A {
private: int a;
public:
    virtual void Print() = 0; //纯虚函数
    void fun() { cout << "fun"; }
};
  • 包含纯虚函数的类叫抽象类
     抽象类只能作为基类来派生新类使用,不能创建抽象类的对象
     抽象类的指针和引用可以指向由抽象类派生出来的类的对象
A a ; // 错, A 是抽象类,不能创建对象
A * pa ; // ok,可以定义抽象类的指针和引用
pa = new A ; //错误, A 是抽象类,不能创建对象
  • 在抽象类的成员函数内可以调用纯虚函数,但是在构造函数或析构函数内部
    不能调用纯虚函数。
  • 如果一个类从抽象类派生而来,那么当且仅当它实现了基类中的所有纯虚函
    数,它才能成为非抽象类。
class A {
public:
    virtual void f() = 0; //纯虚函数
    void g() {
        this->f(); //ok
    }
    A() { //f( ); // 错误
    }
};
class B :public A {
public:
    void f() { cout << "B:f()" << endl; }
};
int main() {
    B b;
    b.g();
    return 0;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342