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.