2009-09-24 5 views
26

Мне интересно, можно ли передать класс в качестве параметра в C++. Не передавать объект класса, но сам класс, который позволит мне использовать этот класс следующим образом.C++ Передача класса в качестве параметра

void MyFunction(ClassParam mClass) 
{ 
    mClass *tmp = new mClass(); 
} 

Вышеупомянутый не настоящий код, но, надеюсь, он объясняет, что я пытаюсь сделать в примере.

ответ

37

Вы можете использовать шаблоны сделать что-то подобное (но не точно, что):

template<class T> 
void MyFunction() 
{ 
    T *tmp = new T(); 
} 

и назвать его MyFunction<MyClassName>().

Обратите внимание, что таким образом вы не можете использовать «переменную» вместо T. Он должен быть известен во время компиляции.

19

C++ не хранит метаданные о классах, как это делают другие языки. Предполагая, что вы всегда использовать класс с конструктором без параметров, вы можете использовать шаблоны для достижения того же:

template <typename T> 
void MyFunction() 
{ 
    T* p = new T; 
} 
+0

Как и другие lanaguages ​​ Не все языки хранят метаданные о программе. Это относительно новая особенность современных языков. –

+1

@ Мартин, это интересное определение «относительно новое», учитывая, что Smalltalk, который был довольно мейнстримом в свое время и имел довольно много кода, написанных на нем, сделал именно это в 70-х годах :) –

+1

Как и многие вещи, приписываемые Smalltalk, Lisp был там в 1950-х годах - вся программа была структурой данных, которую можно было проверять и манипулировать. –

0

Вы можете создать статический метод фабрики на классе (ов), который просто возвращает новый экземпляр класса а затем вы можете передать указатели на эту функцию аналогично тому, что вы хотите сделать в своем примере. Типы возврата являются ковариантными, поэтому, если все ваши классы реализуют один и тот же интерфейс, вы можете вернуть указатель функции этому интерфейсу. Если у них нет общего интерфейса, вы, вероятно, останетесь с возвратом void *. В любом случае, если вам нужно использовать конкретный подкласс, вам нужно будет dynamic_cast.

2

Вы также можете передать указатель на функцию, который при вызове создает экземпляр того, что вы хотите, и возвращает это.

void MyFunction(ClassCreatorPtr makeClassFn) 
{ 
    void * myObject = makeClassFn(); 
} 

Вам нужно, чтобы он возвращал указатель на базовый класс, чтобы делать с ним что-нибудь действительно интересное.

0

Альтернативой шаблонам является использование лямбда-закрытия с C++ 11. Вот мои предпочтения.

// in header file 
IClass * MyFunctionThatDoesStuff(const IParams & interface_params, 
    std::function<IClass * (const IParams & interface_params)> cls_allocator); 

// in source file 
IClass * MyFunctionThatDoesStuff(const IParams & interface_params, 
    std::function<IClass * (const IParams & interface_params)> cls_allocator) { 
    // Some processing. Perhaps the interface_params are generated 
    // inside this function instead of being passed to it. 
    IClass * mCls = cls_allocator(interface_params); 
    // Do whatever with mCls 
    return mCls; 
} 

// Somewhere else in the code. 
{ 
    Param1Type param1 = whatever1; 
    Param2Type param1 = whatever2; 
    // param1, param2, etc. are parameters that only 
    // SomeClsDerivedFromIClass constructor knows about. The syntax &param1 
    // achieves the closure. 
    // interface_param1 is common to all classes derived from IClass. 
    // Could more than one parameter. These parameters are parameters that 
    // vary from different calls of MyFunctionThatDoesStuff in different 
    // places. 
    auto cls_allocator = 
     [&param1, &param2](const IParams & interface_params)->IClass * { 
      return new SomeCls1DerivedFromIClass(interface_params, 
       param1, param2); 
     }; 
    IClass * mCls = MyFunctionThatDoesStuff(interface_params, 
     cls_allocator); 
} 

// Somewhere else in the code again. 
{ 
    ParamXType paramX = whateverX; 
    ParamYType paramY = whateverY; 
    auto cls_allocator = 
     [&paramX, &paramY](const IParams & interface_params)->IClass * { 
      return new SomeCls2DerivedFromIClass(interface_params, 
       paramX, paramY); 
     }; 
    IClass * mCls = MyFunctionThatDoesStuff(interface_params, 
     cls_allocator); 
} 

Вышеупомянутая идея кода хорошо подходит для быстрого построения шаблона или изменения заводского шаблона. Лямбда - это в основном заводский метод. Чтобы сделать его еще более динамичным, вы можете использовать auto для ввода параметров. Что-то вроде этого.

auto * MyFunctionThatDoesStuff(const auto & interface_params, 
    std::function<auto * (const auto & interface_params)> cls_allocator); 

Я прихожу к этому из влияния Python, где вы можете просто передать тип класса функции.

Смежные вопросы