Каковы хорошие методы для получения имени класса в C ++? - PullRequest
0 голосов
/ 21 февраля 2019

Я не говорю о typeid, я просто ищу общий метод для привязки одного объекта (например, std :: string, как в моем случае) к объектам некоторого класса и превращения его получателя в полиморфный или что-то в этом роде.Я не могу дать правильное определение, так что я думаю, что это похоже на проблему получения имени класса, но вы устанавливаете его где-то самостоятельно, и единственные проблемы - где вы его устанавливаете и как вы его возвращаете.

Я просто приведу несколько примеров, которые делают то, что я хочу, но не настолько эффективны, как мне бы хотелось.

  • virtual string GetClassName() const { return string("MyClass"); } - занимает дополнительное время на сборку и копированиестрока каждый раз, когда она называется
  • const string& GetClassName() const { return class_name_; }, где class_name_ - это поле защищенного класса, которое устанавливается в конструкторе - одна и та же строка хранится в каждом объекте, поэтому она неэффективна для памяти

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

Есть идеи?

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

Я думаю, что вам нужна некоторая база NamedClass с virtual std::string_view getName() const, которая возвращает имя производного класса.Таким образом, вы хотите что-то вроде typeid(object).name(), но без искажения имени.

Каждый класс, производный от NamedClass, должен переопределить getName и вернуть имя класса.

class NamedClass {
public:
  virtual std::string_view getName() const = 0;
};

class Derived final : public NamedClass {
public:
  std::string_view getName() const override {
    return "Derived";
  }
};

Если выненавидя это дублирование так же сильно, как и я, вы можете использовать макрос.

#define GET_NAME(NAME) \
  std::string_view getName() const override { return #NAME; }

class Derived final : public NamedClass {
public:
  GET_NAME(Derived)
};

Я настоятельно рекомендую использовать std::string_view вместо const std::string &, если все, что вы хотите сделать, это «просмотреть» строку.

0 голосов
/ 21 февраля 2019

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

Стандарт C ++ дает вам typeid(), который работает во всех случаях, включая встроенные типы, пользовательские классы, полиморфные классы, множественное наследование, виртуальное наследование и тому подобное.тот.

Теперь вам могут не понравиться имена, используемые typeid(), которые зависят от реализации.Или вы можете расширить доступную информацию с помощью собственных расширений управления типами.В этом случае Бьярн Страуструп предложил в « Проектирование и развитие C ++ » очень простое и эффективное решение.

typeid() возвращает ссылку на const std::type_info.Теперь вы можете использовать адрес этого объекта в unordered_map, чтобы сопоставить тип с вашей собственной пользовательской информацией, которая может предоставить желаемое имя.

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

Вот небольшое и быстрое доказательство концепции (конечно, должно быть улучшено):

// Basic principle of the idea
map<const type_info*, string> mytypes;  

template <class T>
const string& mytype(T &&x) {
    return mytypes[&typeid(x)];
}

// Some test types 
struct A { virtual int test() {} };
struct B : A {}; 

int main() {
    // To be improved:  initialization of the type info extension 
    mytypes[&typeid(int)]="Plain C++ integer";
    mytypes[&typeid(A)]="Structure A";
    mytypes[&typeid(B)]="Structure B";

    // demo, including polymorphic type     
    int a; 
    A * p = new B;
    cout << typeid(int).name() <<endl; 
    cout << mytype(a) <<endl; 
    cout << mytype(*p) <<endl; 
    return 0;
}

Демо онлайн

...