Вот мой лучший выстрел для резюме вопроса:
Когда несколько отдельных классов наследуют каждый из нескольких отдельных баз
классы, как мне использовать механизм наследования, чтобы написать функцию
что принимает объекты из нескольких этих базовых классов в качестве параметров?
Но лучше объяснить на примере.
У меня есть библиотека, которая предоставляет следующие классы в своем API:
class A{..};
class B{..};
Эти классы предназначены для того, чтобы скрыть сложность шаблонов от используемого приложения. Реализация включает в себя шаблоны:
template <Type1>
class AImpl: public A{..};
template <Type2>
class BImpl: public B{..};
Проблема в том, что мне нужна функция вроде:
void foo(A insta,B instb);
Механизм наследования, кажется, не очень мне здесь помогает, так как если функция находится внутри AImpl
для него нет возможности автоматически выбрать правильное Type2
за BImpl
(без списка динамических приведений).
Мое лучшее решение на данный момент — дважды шаблонировать один из классов:
template <Type1,Type2>
class BImpl: public B{
void foo(A insta);
};
Но этот подход, похоже, не распространяется на ситуацию, когда было бы полезно объединить A
а также B
с несколькими произвольно заданными экземплярами (для этого требуется динамическое приведение, которое работало бы только в том случае, если был уверен, что параметр insta
был на самом деле AImpl<Type2>
— или вышеупомянутый список приведений).
Не добавляя сложности пользователю A
а также B
Можно ли сделать то, что я пытаюсь сделать здесь, или есть более идиоматический подход?
Спасибо всем.
Это может быть неуместно в свете ответа Барта ван Ингена Шенау, но в ответ на запросы Наваза и Энди Провла я сформулировал следующий файл примера. Для этого нужна библиотека PCL, но это рабочий код (хотя это урезанный пример того, чего я пытаюсь достичь).
Спасибо всем за ваш вклад.
Класс Features
аналогично A
выше и Keypoint
в B
выше. Я добавил тег PCL к вопросу тоже.
#include <pcl/features/fpfh.h> //gives pcl::PointCloud, pcl::FPFHSignature33, etc.
//interface
class Keypoints{
public:
virtual unsigned int size();
//more virtual methods here
};
class Features{
public:
virtual unsigned int size();
//more virtual methods here
};
//implementation
template<typename KeypointType>
class KeypointsImpl:public Keypoints{
public:
typename pcl::PointCloud<KeypointType>::Ptr keypoints_;
virtual unsigned int size(){ return keypoints_->size();}
//more implementations of virtual methods here
};
template<typename FeatureType>
class FeaturesImpl:public Features{
public:
typename pcl::PointCloud<FeatureType>::Ptr features_;
virtual unsigned int size(){ return features_->size();}
//more implementations of virtual methods here
};
//void removeBadFeatures(Keypoints k,Features f); //<-- would like to have this too
int
main (int argc, char ** argv)
{
//Class construction could be done anywhere.
Features *f = new FeaturesImpl<pcl::FPFHSignature33>();
Keypoints *k = new KeypointsImpl<pcl::PointXYZ>();
int a = f->size();
int b = k->size();
//removeBadFeatures(k,f); //will alter f and k in concert
}
Если я вас правильно понимаю, вы пишете библиотеку, которая использует несколько независимых шаблонов (Aimpl
, Bimpl
, так далее.). Чтобы скрыть этот факт от пользователей библиотеки, вы выставляете только не шаблонные базовые классы этих шаблонов (A
, B
, так далее.).
Теперь у вас есть функция foo
он должен работать с двумя шаблонными типами, передаваемыми как ссылки на их базовые классы, и вы сталкиваетесь с проблемой, которую вы не можете (легко) определить, к каким шаблонам относятся параметры.
Есть только несколько вариантов решения этой дилеммы:
foo
полностью с точки зрения операций, которые работают с базовыми классами (поскольку это вся информация, которая foo
есть).dynamic_cast
s, чтобы определить, с каким производным классом вы работаете. (Лучше всего избегать этой опции, если это возможно, потому что это настоящий кошмар.)Других решений пока нет …