简体   繁体   中英

Accessing sub class's member functions through base class pointer

I am trying to write a class that uses DOM to write a list of Registrations to file as XML. The list of registrations contains three types of registration Registration which is the standard base registration class GuestRegistration and StudentRegistration which both derive from Registration .

The GuestRegistration class has a unique member category and the student registration has unique member qualification .

When I iterate over the list of registration pointers I only have access to the base class Registration 's member functions. Is there any way I can access the subclasses' data members to use the getter functions getCategory and getQualification ? I've tried creating a GuestRegistration and StudentRegistration pointer whenever the class name matches either of the two, but get a pointer conversion error.

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());

    }
}

You can use dynamic_cast to check for specific sub-classes:

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());    
    }
}

However, I would suggest implementing a virtual method in the Registration class itself that your sub-classes can override to register additional items as needed, eg:

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());    
    }
}

Alternatively:

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());    
    }
}

The straightforward C++ tool is dynamic_cast<>().

In general it is not good practice to initially design a project that requires such cast. Various design pattern may be considered.

I see that you are using metaObject() , so it means that Registration has QObject as a base class. In that case it is possible to use 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.

您可以让基类提供派生类用于编写类特定数据的接口,而不是使用dynamic_cast

Probably you need to make the methods virtual. Non virtual method use the methods of the class used at compile time, virtual methods of subclasses are chosen instead at runtime.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM