У меня есть такие классы:
class ParkingLot
{
public:
int spaces;
virtual bool something() { return true; }
}
class ParkingLotBuilding
{
public:
ParkingLot Floor1, Floor2;
}
У меня есть множество функций, которые принимают ParkingLotBuilding. Допустим, кто-то (я) происходит от ParkingLot и ParkingLotBuilding:
class DerivedParkingLot : public ParkingLot
{
public:
virtual bool something() { return false; }
}
class DerivedParkingLotBuilding : public ParkingLotBuilding
{
public:
// how can I make it so that Floor1 and Floor2 are for DerivedParkingLot?
}
У меня есть функции, которые я не контролирую, как это:
CheckBuilding( ParkingLotBuilding &building )
{
if(building.Floor1.something() == true)
// error
}
Если я передам объект DerivedParkingLotBuilding этой функции, как мне сделать так, чтобы он вызывал DerivedParkingLot :: something () для возврата false? Это возможно? Извините, если я не объяснил это правильно, я не уверен, как спросить о проблеме. Спасибо
Как отметил ДжонСмит, вы не можете переопределять элементы данных, только функции-члены. поскольку ParkingLotBuilding
содержит ParkingLot
ценности, а не ParkingLot
указатели или ссылки, они не могут быть использованы полиморфно, даже в DerivedParkingLot
, (Именно так работает C ++: только указатели и ссылки могут иметь динамический тип.)
Это означает, что если вы не можете изменить ParkingLotBuilding
класс (или CheckBuilding
функция), то вы застряли. Вы не можете получить ничего такого, что получит CheckBuilding
функция для работы на DerivedParkingLot
объект.
Мораль этой истории в том, что классы должны быть разработаны для наследования с самого начала.
На самом деле вы просто вызываете функцию DerivedParkingLot из экземпляра ParkingLot?
Ваш код уже сделал это, указав метод some как виртуальный, он будет автоматически искать самый низкий метод в своем унаследованном дереве.
Простой способ проверить это состоит в том, чтобы реализовать метод «что-то» в ParkingLot и DerivedParkingLot, поместить в каждое сообщение и проверить его.
Один из способов, которым вы могли бы подойти к этому, это сделать ParkingLot
шаблон класса.
template<typename T>
class ParkingLotBuilding
{
public:
T Floor1, Floor2;
}
Затем при создании ParkingLotBuilding
Вы можете использовать эти типы:
ParkingLotBuilding<ParkingLot>
ParkingLotBuilding<DerivedParkingLot>
Также, если вы не любите шаблонизировать все время и хотите просто использовать ParkingLotBuilding
а также DerivedParkingLotBuilding
, вы можете переименовать класс в нечто вроде Building
и используйте typedefs:
typedef Building<ParkingLot> ParkingLotBuilding
typedef Building<DerivedParkingLot> DerivedParkingLotBuilding
Этот подход не совсем наследование между ParkingLotBuilding
типы (и, возможно, не лучший подход — я никогда не видел этого раньше), но он может делать то, что вам нужно.
В вашем примере, Floor1 не может узнать, был ли он создан внутри ParkingLotBuilding или DerivedParkingLotBuilding.
Вы могли бы использовать RTTI, чтобы иметь дело с этим что-то вроде:
CheckBuilding (ParkingLotBuilding *building)
{
if (dynamic_cast<DerivedParkingLogBuilding*>(building))
{
// Floor is in a derived parking log building
}
else
{
// Floor is in a parking lot building
}
}
Хотя, как указывалось выше, не совсем лучшим было сделать это.