通过基类指针访问子类的成员函数

Accessing sub class's member functions through base class pointer

本文关键字:成员 函数 子类 访问 基类 指针      更新时间:2023-10-16

我正在尝试编写一个使用DOM编写注册列表的类作为XML文件。注册列表包含三种类型的注册:Registration是标准基注册类,GuestRegistrationStudentRegistration均派生自Registration

GuestRegistration类有唯一成员category,学生注册有唯一成员qualification

当我迭代注册指针列表时,我只能访问基类Registration的成员函数。是否有任何方法我可以访问子类的数据成员使用getter函数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());
    }
}

您可以使用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());    
    }
}

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

一般来说,最初设计一个需要这种类型转换的项目并不是一个好的实践。可考虑多种设计模式

我看到你正在使用metaObject(),所以这意味着RegistrationQObject作为基类。在这种情况下,可以使用qobject_cast:

qobject_cast()函数的行为类似于标准c++dynamic_cast(),其优点是不需要RTTI它可以跨动态库边界工作。

不使用dynamic_cast,您可以让基类提供一个接口,派生类使用它来编写特定于类的数据。

可能需要将这些方法设置为虚拟的。非虚方法使用在编译时使用的类的方法,而在运行时选择子类的虚方法。