2015-09-25 124 views
3

我正在嘗試編寫一個類,該類使用DOM將註冊列表寫入XML文件。註冊清單包含三種類型的註冊Registration,這是標準基礎註冊類別GuestRegistrationStudentRegistration,這兩種註冊均來自Registration通過基類指針訪問子類的成員函數

GuestRegistration類有一個獨特的成員category和學生註冊有獨特的成員qualification

當我迭代註冊指針列表時,我只能訪問基類Registration的成員函數。有什麼方法可以訪問子類的數據成員以使用吸氣功能getCategorygetQualification?我試着創建一個GuestRegistrationStudentRegistration指針,只要類名與兩者中的任何一個匹配,但得到指針轉換錯誤。

void RegistrationListWriter::write(RegistrationList r) { 
    QList<Registration*> regList = r.getRegistrationList(); 

    for (int i = 0; i < regList.size(); ++i) { 
     QString cn = regList.at(i)->metaObject()->className(); 
     Person tempPerson = regList.at(i)->getAttendee(); 

     appendRegistrationAndType(cn); 
     appendAttendee(tempPerson); 
     //this is where my issue starts 
     if (cn == "GuestRegistration") { 
      GuestRegistration guestReg = regList.at(i); 
      appendAttendeeCatagory(guestReg.getCatagory()); 
     } 

     if (cn == "StudentRegistration") { 
      StudentRegistration* stuReg = regList.at(i); 
      appendAttendeeQualification(stuReg->getQualification()); 
     } 

     appendBookingDate(regList.at(i)->getBookingDate().toString()); 
     appendRegistrationFee(regList.at(i)->calculateFee()); 

    } 
} 
+1

你應該能夠做一個'dynamic_cast'這兩個指針類型,如果你回來不是'nullptr'你將有機會獲得子類方法的其他任何。 –

回答

5

您可以使用dynamic_cast檢查具體的子類:

void RegistrationListWriter::write(RegistrationList r) { 
    QList<Registration*> regList = r.getRegistrationList(); 

    for (int i = 0; i < regList.size(); ++i) { 
     Registration *reg = regList.at(i); 

     appendRegistrationAndType(reg->metaObject()->className()); 
     appendAttendee(reg->getAttendee()); 

     if (GuestRegistration *guestReg = dynamic_cast<GuestRegistration*>(reg)) { 
      appendAttendeeCatagory(guestReg->getCatagory()); 
     } 
     else 
     if (StudentRegistration* stuReg = dynamic_cast<StudentRegistration*>(reg)) { 
      appendAttendeeQualification(stuReg->getQualification()); 
     } 
     // and so on ... 

     appendBookingDate(reg->getBookingDate().toString()); 
     appendRegistrationFee(reg->calculateFee());  
    } 
} 

不過,我會建議在Registration類本身實現虛擬方法,你的子類可以覆蓋註冊其他項目,如需要如:

class Registration { 
    ... 
    virtual void appendExtraAttendees(RegistrationListWriter *writer){} 
    ... 
}; 

class GuestRegistration : public Registration { 
    ... 
    virtual void appendExtraAttendees(RegistrationListWriter *writer); 
    ... 
}; 

void GuestRegistration::appendExtraAttendees(RegistrationListWriter *writer){ 
    writer->appendAttendeeCatagory(getCatagory()); 
} 

class StudentRegistration : public Registration { 
    ... 
    virtual void appendExtraAttendees(RegistrationListWriter *writer); 
    ... 
}; 

void StudentRegistration::appendExtraAttendees(RegistrationListWriter *writer){ 
    writer->appendAttendeeQualification(getQualification()); 
} 

void RegistrationListWriter::write(RegistrationList r) { 
    QList<Registration*> regList = r.getRegistrationList(); 

    for (int i = 0; i < regList.size(); ++i) { 
     Registration *reg = regList.at(i); 

     appendRegistrationAndType(reg->metaObject()->className()); 
     appendAttendee(reg->getAttendee()); 

     reg->appendExtraAttendees(this); 

     appendBookingDate(reg->getBookingDate().toString()); 
     appendRegistrationFee(reg->calculateFee());  
    } 
} 

或者:

class Registration { 
    ... 
    virtual void appendAttendees(RegistrationListWriter *writer); 
    ... 
}; 

void Registration::appendAttendees(RegistrationListWriter *writer){ 
    writer->appendAttendee(getAttendee()); 
} 

class GuestRegistration : public Registration { 
    ... 
    virtual void appendAttendees(RegistrationListWriter *writer); 
    ... 
}; 

void GuestRegistration::appendAttendees(RegistrationListWriter *writer){ 
    Registration::appendAttendees(writer); 
    writer->appendAttendeeCatagory(getCatagory()); 
} 

class StudentRegistration : public Registration { 
    ... 
    virtual void appendAttendees(RegistrationListWriter *writer); 
    ... 
}; 

void StudentRegistration::appendAttendees(RegistrationListWriter *writer){ 
    Registration::appendAttendees(writer); 
    writer->appendAttendeeQualification(getQualification()); 
} 

void RegistrationListWriter::write(RegistrationList r) { 
    QList<Registration*> regList = r.getRegistrationList(); 

    for (int i = 0; i < regList.size(); ++i) { 
     Registration *reg = regList.at(i); 

     appendRegistrationAndType(reg->metaObject()->className()); 

     reg->appendAttendees(this); 

     appendBookingDate(reg->getBookingDate().toString()); 
     appendRegistrationFee(reg->calculateFee());  
    } 
} 
+0

非常感謝您的詳細解答@Remy Lebeau爲什麼創建虛擬函數比使用dynamic_cast或QObject_cast更好? – user2094257

+0

'dynamic_cast'具有開銷,因爲它必須在運行時執行RTTI查找以確定源對象是否與請求的類相關並返回適當的指針。另外,如果將來添加更多派生類,則必須添加更多'dynamic_cast'檢查。通過虛擬方法調用,可以避免查找。調用虛擬方法很簡單,它是對象vtable的簡單索引,因此調用會在運行時直接跳轉到大部分派生的實現。調用代碼不必關心派生類的細節。 –

0

可能您需要使方法變爲虛擬。 非虛擬方法使用編譯時使用的類的方法,而是在運行時選擇虛擬子類的方法。

1

而不是使用dynamic_cast的,你可以有基類提供的派生類用來寫自己的類特定數據的接口。

2

直接的C++工具是dynamic_cast <>()。

總的來說,最初設計一個需要這種鑄造的項目並不是好習慣。可以考慮各種設計模式。

我看到你正在使用metaObject(),所以這意味着RegistrationQObject作爲基類。在這種情況下,可以使用qobject_cast

The qobject_cast() function behaves similarly to the standard C++ dynamic_cast(), with the advantages that it doesn't require RTTI support and it works across dynamic library boundaries.

+0

當我使用QObject_cast時,出現以下錯誤: C:\ Qt \ Qt5.3.0 \ 5.3 \ mingw482_32 \ include \ QtCore \ qobject.h:-1:在複製構造函數'RegistrationList :: RegistrationList(const RegistrationList&)' : C:\ Qt \ Qt5.3.0 \ 5.3 \ mingw482_32 \ include \ QtCore \ qobject.h:465:error:'QObject :: QObject(const QObject&)'是私有的 Q_DISABLbE_COPY(QObject) ^ – user2094257

+0

@ user2094257無法將基類實例投射到派生實例。它只能投射指針:'qobject_cast (base_ptr)',其中'base_ptr'是指向基類實例'(Registration *)'的指針。 –