溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C++中的多態(tài)用法總結(jié)

發(fā)布時(shí)間:2020-08-05 05:51:17 來源:網(wǎng)絡(luò) 閱讀:386 作者:玉心軟件 欄目:編程語言

1,父類中的方法加virtual與不加virtual的區(qū)別

先定義兩個(gè)bean。BaseBeanUserBean。UserBean繼承于BaseBean。BaseBean中含有兩個(gè)屬性id(int類型)create_timestd::string類型)。UserBean中含有屬性namestd::string類型)。定義兩個(gè)類BaseModelUserModelUserModel繼承于BaseModel。BaseModel中定義了一個(gè)方法virtual int addRecord(BaseBean *);其定義如下:

int BaseModel::addRecord(BaseBean *data)

{

        std::cout << "base" << std::endl;

        return 0;

}

UserModel中重新聲明int addRecord(BaseBean *);并定義這個(gè)方法:

int UserModel::addRecord(BaseBean *data)

{

    std::cout << "user" << std::endl;

    return 0;

}

main函數(shù)中測(cè)試這兩個(gè)類的addRecord方法:

    BaseModel base;

    UserModel user;

    BaseModel *basePtrOfBase = new BaseModel;

    BaseModel *basePtrOfUser = new UserModel;

    BaseModel &baseRefOfBase = base;

    BaseModel &baseRefOfUser = user;

    BaseModel baseOfUser = user;

    UserBean userBean;

    userBean.setId(1);

    userBean.setName("first user");

    std::cout << "base:";

    base.addRecord(&userBean);

    std::cout << "user:";

    user.addRecord(&userBean);

    std::cout << "basePtrOfBase:";

    basePtrOfBase->addRecord(&userBean);

    std::cout << "basePtrOfUser:";

    basePtrOfUser->addRecord(&userBean);

    std::cout << "baseRefOfBase:";

    baseRefOfBase.addRecord(&userBean);

    std::cout << "baseRefOfUser:";

    baseRefOfUser.addRecord(&userBean);

    std::cout << "baseOfUser:";

baseOfUser.addRecord(&userBean);

運(yùn)行結(jié)果如下:

C++中的多態(tài)用法總結(jié)C++中的多態(tài)用法總結(jié)

現(xiàn)在,將BaseModel中的addRecord方法聲明語句中的virtual去掉,再次運(yùn)行結(jié)果如下:

C++中的多態(tài)用法總結(jié)

通過將兩次運(yùn)行結(jié)果進(jìn)行對(duì)比,可以看出差異主要在BaseModel *basePtrOfUser = new UserModel;BaseModel &baseRefOfUser = user;定義的實(shí)例調(diào)用中。所以對(duì)于父類中的方法加virtual與不加virtual主要影響的就是使用父類聲明的指針或引用對(duì)象中。如果使用父類聲明的指針或引用對(duì)象是使用子類來實(shí)例化的。則其調(diào)用父類中含有virtual方法時(shí),會(huì)調(diào)用實(shí)例化的子類中的該方法(如果子類中有重寫了這個(gè)方法的話)。

 

2,多態(tài)的使用

在使用父類類型作為函數(shù)的形參類型時(shí),要注意傳遞的普通對(duì)象和指針及引用的區(qū)別。還是以上面的BaseModelUserModel為例。先定義在BaseModel中聲明以下幾個(gè)函數(shù):

    int addRecord(BaseBean );

    virtual int addRecordPrc(BaseBean ) = 0;

virtual int getList(std::list<BaseBean> *rtnList) = 0;

addRecord的定義如下:

int BaseModel::addRecord(BaseBean data)

{

    data.setCreateTime("2019-02-16");

    return this->addRecordPrc(data);

}

UserModel中對(duì)addRecordPrcgetList的定義如下:

int UserModel::addRecordPrc(BaseBean data)

{

    UserBean *user = static_cast<UserBean *>(&data);

       std::cout << user->getId() << std::endl;

std::cout << user->getCreateTime().c_str() << std::endl;

return 0;

}

 

int UserModel::getList(std::list<BaseBean> *rtnList)

{

    UserBean user1;

    user1.setId(1);

    user1.setName("user1");

    user1.setCreateTime("2019-02-15");

    rtnList->push_back(user1);

    UserBean user2;

    user2.setId(2);

    user2.setName("user2");

    user2.setCreateTime("2019-02-16");

    rtnList->push_back(user2);

return 0;

}

現(xiàn)在調(diào)用UserModel中的addRecord方法。

UserModel userModel;

    UserBean userBean;

    userBean.setId(1);

    userBean.setName("first user");

userModel.addRecord(userBean);

運(yùn)行結(jié)果:

C++中的多態(tài)用法總結(jié)

現(xiàn)在,在addRecordPrc中加上std::cout << user->getName().c_str() << std::endl;再次運(yùn)行程序,運(yùn)行結(jié)果如下:

C++中的多態(tài)用法總結(jié)

可以看到,程序在運(yùn)行到輸出username時(shí)崩潰了。這是為什么呢?

現(xiàn)在我們把addRecord的形參類型改為BaseBean *,addRecordPrc的形參不變,調(diào)整代碼再次運(yùn)行,發(fā)現(xiàn)結(jié)果與之前一樣。將addRecord的形參類型改為BaseBean,而addRecordPrc的形參類型改為BaseBean *,調(diào)整代碼再次運(yùn)行,結(jié)果還是與之前一樣。將addRecordaddRecordPrc的形參類型都改為BaseBean *,調(diào)整代碼再次運(yùn)行程序。程序終于可以正常運(yùn)行了。運(yùn)行結(jié)果如下:

C++中的多態(tài)用法總結(jié)

那這到底是為什么呢?為什么使用BaseBean指針就可以,而直接使用BaseBean對(duì)象就會(huì)導(dǎo)致程序崩潰呢?

當(dāng)addRecord的參數(shù)類型是BaseBean時(shí),addRecord的參數(shù)變量data只能獲取到了設(shè)定的idcreate_time兩個(gè)屬性的值,即只是將調(diào)用時(shí)傳遞的參數(shù)userBean中的屬性的值拷貝給了data,且只拷貝了idcreate_time屬性,因?yàn)?/span>data變量沒有name屬性,所以data變量不能獲取到設(shè)定的name屬性的值。這時(shí),即使它被指針的方式傳遞給addRecordPrcaddRecordPrc的參數(shù)變量獲取到的name也是null。而當(dāng)addRecord的參數(shù)類型是BaseBean *時(shí),addRecord的參數(shù)變量data獲取到的是一個(gè)指向包含id,namecreate_time三個(gè)屬性值的內(nèi)存的地址,所以,data能夠到獲取到這三個(gè)屬性的值。此時(shí)如果在addRecord中輸出name,是可以成功的。向addRecordPrc的參數(shù)傳遞與此相同。

接下來測(cè)試下getList方法:

    std::list<BaseBean> userList;

    userModel.getList(&userList);

    for(std::list<BaseBean>::iterator it = userList.begin(); it != userList.end();it++)

    {

        UserBean *u = static_cast<UserBean *>(&(*it));

        cout << u->getId() << endl;

        cout << u->getCreateTime().c_str() << endl;

        cout << u->getName().c_str() << endl;

}

運(yùn)行結(jié)果:

C++中的多態(tài)用法總結(jié)

程序崩潰的原因和調(diào)用addRecord時(shí)相同。調(diào)用getList方法時(shí)傳遞的userList中的元素只能獲取到從getList方法體中設(shè)定的元素的拷貝值。而userList的元素是BaseBean類型,所以只能獲取到idcreate_time屬性的值。將userList中的元素改為BaseBean *,即將getList的參數(shù)類型改為std::list<BaseBean *>*,調(diào)整程序,再次運(yùn)行程序,運(yùn)行結(jié)果為:

C++中的多態(tài)用法總結(jié)

程序正常。這里要注意,改為std::list<BaseBean *>*后,不能簡單的將原來的rtnList->push_back(user1);改為rtnList->push_back(&user1);。這是因?yàn)?/span>user1getList函數(shù)中的局部變量。當(dāng)getList函數(shù)執(zhí)行完畢后,user1的生命周期就結(jié)束了,它的內(nèi)存空間將會(huì)被釋放。這時(shí)如果再執(zhí)行上述調(diào)用,將會(huì)直接導(dǎo)致程序崩潰,而不是像上面那樣執(zhí)行到getName才崩潰。正確的做法是使用new。即:UserBean *user1 = new UserBean;。使用new時(shí),千萬不要忘記在調(diào)用完后調(diào)用delete釋放內(nèi)存空間。如下所示:

    for(std::list<BaseBean *>::iterator it = userList.begin(); it != userList.end();it++)

    {

        UserBean *u = static_cast<UserBean *>((*it));

        cout << u->getId() << endl;

        cout << u->getCreateTime().c_str() << endl;

        cout << u->getName().c_str() << endl;

        delete u;

    }


源代碼路徑:https://pan.baidu.com/s/1-z5fCUkLTGvaGPXafC__Gg  提取碼:b7os

這份源代碼是基于Qt Creator寫的。如果需要直接編譯運(yùn)行,可以通過Qt Creator直接打開源代碼。


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI