Пожалуйста, рассмотрите эту иерархию классов:
#include <iostream>
struct Base
{
Base(int arg1, int arg2, int arg3, int arg4)
{
std::cout << "Base::Base:" << arg1 << "," << arg2 << "," << arg3 << "," << arg4 << std::endl;
}
void BaseDoWork()
{
std::cout << "Base::BaseDoWork" << std::endl;
}
};
struct Derived1:public Base
{
Derived1(int arg1, int arg2, int arg3, int arg4):Base(arg1, arg2, arg3, arg4){}
void DerivedDoWork()
{
BaseDoWork();
}
};
struct Derived2:public Derived1
{
Derived2(int arg1, int arg2, int arg3, int arg4):Derived1(arg1, arg2, arg3, arg4){}
};
int main(int argc, char *argv[])
{
Derived2 myDerived2(1,2,3,4);
myDerived2.DerivedDoWork();
return 0;
}
Класс Derived1 имеет больше связей, чем мне бы хотелось: он должен знать, как создать «базовый» класс. В глубокой иерархии это будет означать распространение аргументов для конструктора «Базового» класса на всем протяжении иерархии классов. Изменение конструктора класса «Base» потребует изменения всех производных классов.
Мои цели для этой иерархии классов:
Derived1 ожидает метод BaseDoWork () в базовом классе, но ему не нужно знать, как создать базовый класс.
Derived2 знает, как создать «базовый» класс.
В идеале я хотел бы сделать Derived1 шаблоном, принимающим любой базовый класс с доступным методом «BaseDoWork ()», по следующим направлениям:
template <T> struct Derived1:public T
{
void DerivedDoWork()
{
BaseDoWork();
}
};
Но если я создаю экземпляр вышеупомянутого шаблона как Derived1<Base>
Я не могу понять, как создать «базовый» класс, не добавив знания об «базовых» аргументах конструктора в Derived1.
Предполагая, что это реальная иерархия, если Derived1
это Base
производный класс, должен знать, как создать родительский класс (Base
).
Как я понял, может я и ошибаюсь, если Derived1
на самом деле не Base
производный (дочерний) класс, и ему нужно только знать его интерфейс, не нужно знать, как создать Base
пример. Таким образом, вы можете определить Derived1 следующим образом:
struct Derived1
{
Derived1(int arg1, int arg2, int arg3, int arg4)
{}
.....
};
Только Base
производные классы должны знать, как строить Base
:
struct Derived2 : public Base
{
Derived2(int arg1, int arg2, int arg3, int arg4) :
Base(arg1, arg2, arg3, arg4)
{}
.....
};
Сейчас если Derived2
действительно Derived1
ребенок, должен знать, как создать своего родителя. Предыдущий код стал:
struct Derived2 : public Base, public Derived1
{
Derived2(int arg1, int arg2, int arg3, int arg4) :
Base(arg1, arg2, arg3, arg4),
Derived1(arg1, arg2, arg3, arg4)
{}
.....
};
Если вы должны использовать Base::BaseDoWork()
метод из Derived1
Вы можете определить классы следующим образом:
struct Base
{
Base(int arg1, int arg2, int arg3, int arg4)
{
std::cout << "Base::Base:" << arg1 << "," << arg2 << "," << arg3 << "," << arg4 << std::endl;
}
virtual void BaseDoWork()
{
std::cout << "Base::BaseDoWork" << std::endl;
}
};
struct Derived1
{
Derived1(int arg1, int arg2, int arg3, int arg4)
{}
template <typename T>
void DerivedDoWork(T & base) // only knows T interface
{
base.BaseDoWork();
}
};
struct Derived2 : public Base, public Derived1
{
Derived2(int arg1, int arg2, int arg3, int arg4) :
Base(arg1, arg2, arg3, arg4),
Derived1(arg1, arg2, arg3, arg4)
{}
virtual void DerivedDoWork()
{
Derived1::DerivedDoWork<Base>(*(static_cast<Base *>(this)));
}
};
Главное держит то же самое.
Возможно, вам нужно пересмотреть эту иерархию.
Когда вы делаете public
наследование Derived1
от Base
В результате получается, что Derived1
уже знает, как построить Base
так что если хотите Derived1
не знаю, как построить Base
может быть, лучше не наследовать его от Base
? Вместо этого отдельный Base
как какой-то исполнитель.
Рассмотрим этот фрагмент кода, я не утверждаю, что это решение, но, возможно, оно подтолкнет вас к другим мыслям (имена классов совпадают):
#include <iostream>
struct Base
{
Base()
{
std::cout << "Base::Base:" << std::endl;
}
Base(int arg1, int arg2, int arg3, int arg4)
{
std::cout << "Base::Base:" << arg1 << "," << arg2 << "," << arg3 << "," << arg4 << std::endl;
}
void DoWork()
{
std::cout << "Base::BaseDoWork" << std::endl;
}
};
template <typename T>
struct Derived1
{
T object;
Derived1(T obj){ object = obj; }
void DerivedDoWork()
{
object.DoWork();
}
};
template <typename T>
struct Derived2 : public Derived1<T>
{
Derived2(int arg1, int arg2, int arg3, int arg4) : Derived1( T(arg1, arg2, arg3, arg4))
{ }
};
int main(int argc, char *argv[])
{
Derived2<Base> myDerived2(1,2,3,4);
myDerived2.DerivedDoWork();
return 0;
}