0

クラスの階層があり、基本クラスにはクラス名を出力する機能があります。

#include <iostream>
using namespace std;

class base
{
public:
  virtual void print_name() { cout << typeid(*this).name() << endl; };
};

class derived1 : public base { };

class derived2 : public base { };

int main ()
{
  base Base;
  Base.print_name();

  derived1 Derived1;
  Derived1.print_name();

  derived2 Derived2;
  Derived2.print_name();
}

上記の出力は

class base
class derived1
class derived2

実際、これはプラットフォームに依存します。

各クラスに一意の名前を「付ける」多かれ少なかれ標準的な方法があるのでprintname()、すべてのプラットフォームで出力を同じにするために使用できます(実際のクラス名に加えられた変更とは無関係です)?

4

3 に答える 3

2

もちろん:

class base {
  public:
    virtual char const *name() const { return "base"; }
};

class derived1 : public base {
  public:
    virtual char const *name() const { return "derived1"; }
};

ただし、クラスでオーバーライドしない場合name、その名前はそのスーパークラスの名前になります。ユースケースによっては、これはバグまたは機能である可能性があります。バグの場合は、ランタイム チェックを追加して、メソッドがオーバーライドされていることを確認できます。

virtual char const *name() const {
    if (typeid(*this) != typeid(base))
        throw std::logic_error("name() not overridden");
    return "base";
}

nameただし、オーバーライドする必要があるすべての実装でこのチェックを繰り返す必要があります。

于 2012-05-28T11:00:07.277 に答える
1

これを有効活用できますtype_info

type_infoユーザーが指定した述語が提供されている限りbefore、(たとえば) での使用を許可する Weak Order に準拠するメソッドをサポートします。std::map

struct TypeInfoLess {
     bool operator()(std::type_info const* lhs, std::type_info const* rhs) const {
         return lhs->before(rhs);
     }
};

struct AdditionalTypeInfo {
    std::string name;
};

typedef std::map<std::type_info const*, AdditionalTypeInfo, TypeInfoLess> TypeInfoMap;

次に、タイプを追加/検索できます。

template <typename T>
void add(TypeInfoMap& map, T const& t, AdditionalTypeInfo const& ati) {
    map[&typeid(t)] = ati;
}

template <typename T>
AdditionalTypeInfo const* find(TypeInfoMap const& map, T const& t) {
    TypeInfoMap::const_iterator it = map.find(&typeid(t));
    if (it == map.end()) { return 0; }
    return &it->second;
}

int main() {
    TypeInfoMap timap;

    add(timap, timap, { "TypeInfoMap" });

    if (AdditionalTypeInfo const* const ati = find(timap, timap)) {
        std::cout << ati->name << "\n";
    }
}

注: 必要なすべてのタイプをマップに追加するのは、ユーザーの責任です。

于 2012-05-28T11:48:14.730 に答える
0

テンプレート関数 (または特性クラス) を使用して名前を取得できます。

template<typename T> const char * ClassName(T const * objPtr);

template<> const char * ClassName<derived1>(derived1 const *objPtr) { return "derived1"; }
template<> const char * ClassName<derived2>(derived2 const *objPtr) { return "derived2"; }

(ここでは、関数パラメーターはテンプレート パラメーターの一致にのみ使用されます)。また、コードの呼び出しでは、ポインタを特定のクラスにキャストして ClassName を使用できます

derived1 * pDerived = static_cast<derived1*>(pPointer);
cout << ClassName(pDerived);

ただし、これはすべてコンパイル時のものであり、実行時にクラスを識別する (適切なポインター型にキャストする) ためのメカニズム (GUID など) が必要になります。クラスに何もなく、それらを変更できない場合は、私はあなたを助けることができません;(しかし、プラットフォームに依存する型選択コードをローカライズするために、特性テクニックを使用できます。

于 2012-05-28T11:46:10.813 に答える