Можно ли создать такие макросы C ++, которые бы обернули ваш стандартный (унаследованный) класс в приложение? - PullRequest
2 голосов
/ 08 августа 2011

Итак, у нас есть простой интерфейс базового класса:

class animal {
public:
  animal(int age) : age_(age) {
  }
  virtual ~animal(void) {
  }
  virtual std::string get_name(void) {
    return "A generic animal";
  }
  int get_age(void) {
    return age_;
  }
protected:
  int age_;
};

И мы хотим наследовать от него с помощью такого класса:

#include "animal.hpp"
#include "some_includes_for_our_shared_libs.hpp"

class puma : public animal {
 public:
  puma(int age) : animal(age) {}
  virtual std::string get_name() {
    return "puma";
  }
};

Если мы создаем библиотеку - разделяемую или статическую, ее ok мы просто наследуем от нее, но когда мы хотим создать приложение, нам нужно создать некоторую основную функцию и, возможно, добавить некоторые включения. Я хочу создать несколько макросов, которые позволили бы мне создать такой main в случае, если класс компилируется не в разделяемую библиотеку.

Я думаю, это может выглядеть

// puma.cpp
#include "FILE_WITH_MACROS.hpp"
ANIMAL_MACROS_NAME_HERE class puma : public animal {
 public:
  puma(int age) : animal(age) {}
  virtual std::string get_name() {
    return "puma";
  }
};
//end of puma.cpp

И эти макросы получат имя класса и создадут main, который создаст и вызовет наш класс, как если бы он вызывал общий класс animall или просто добавил включения для "animal.hpp" и "some_includes_for_our_shared_libs.hpp".

Таким образом, в случае использования совместно используемого класса lib макросы превращаются в

#include "animal.hpp"
#include "some_includes_for_our_shared_libs.hpp"

class puma : public animal {
 public:
  puma(int age) : animal(age) {}
  virtual std::string get_name() {
    return "puma";
  }
};

А в случае применения классы будут преобразованы макросами в

#include <iostream>
#include "animal.hpp"


class puma : public animal {
 public:
  puma(int age) : animal(age) {}
  virtual std::string get_name() {
    return "puma";
  }
};

int main()
{
int default_age = 4;
puma *an_animal = new puma(default_age);
std::cout << "anmal "<< an_animal->get_name << " created. Its age is " << an_animal->get_age << std::endl;
std::cin.get();
}

Использование: представьте, что у нас есть класс service-base, и мы создали new-service. Наше приложение для основного сервера поддерживает расширения, поэтому к нему можно подключить new-service, так как оно скомпилировано в общую библиотеку. Но что, если мы хотим превратить наш сервис в отдельный сервер? чем нам понадобятся такие макросы, чтобы обернуть его main и, возможно, добавить или удалить #includes.

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

Ответы [ 2 ]

1 голос
/ 08 августа 2011
int main()
{
int default_age = 4;
SERVICECLASS *an_animal = new SERVICECLASS(default_age);
std::cout << "anmal "<< an_animal->get_name << " created. Its age is " << an_animal->get_age << std::endl;
std::cin.get();
}

Затем скомпилируйте с (эквивалент вашего компилятора) -DSERVICECLASS=puma или получите файл с именем что-то вроде «config.h», который включен в main, и который вы можете редактировать без необходимости редактировать любой другой код.

Тогда вы можете определить свои классы животных, как вам нравится. Если вы хотите определить классы так:

#define STRINGIZE_(ARG) #ARG
#define EXPAND_AND_STRINGIZE(ARG) STRINGIZE(ARG)

class SERVICECLASS: public animal {
 public:
  SERVICECLASS(int age) : animal(age) {}
  virtual std::string get_name() {
    return EXPAND_AND_STRINGIZE(SERVICECLASS);
  }
};

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

1 голос
/ 08 августа 2011

Я бы просто сделал так, чтобы main() было тривиальным. Как

int main()
{
    int default_age = 4;
    return puma(default_age).run();
}

и оставьте все как есть.

...