LoginSignup
2
1

More than 5 years have passed since last update.

[C++] 異なる型を一つの配列で管理するクラス

Last updated at Posted at 2016-12-15

追記:
Ryooooooga様にBoostやC++17以降を使う方法を教えていただきました。詳しくはコメントで

void*を使ってるので実際に使うときは十分注意。

test.h
#pragma once
#include <memory>
#include <functional>
#include <vector>
#include <typeindex>

/**
* void*型に変換された実体のデストラクタを正しく読み出すため構造体
* http://faithandbrave.hateblo.jp/entry/2014/06/04/172754
* から参照
*/
struct void_deleter {
    std::function<void(void*)> deleter;

    template <typename F>
    void_deleter(F f)
    {
        deleter = f;
    }

    void operator()(void* p) const noexcept
    {
        deleter(p);
    }

    void_deleter() {};
};

/**
* 型の異なるデータを一つに登録するクラス。
*/
class ObjectClass
{

protected:
    /**
    * 配列.
    */
    std::vector< std::pair < std::unique_ptr<void, void_deleter>, char* > >value_;

public:
    /**
    * コンストラクタ.デストラクタ.
    */
    ObjectClass();
    ~ObjectClass();

    /**
    * 配列の後ろに追加
    * @param val 色々な型データ.
    */
    template <typename T>
    void  push_back(const T &val) {
        // 通常のnewと、void_deleter構造体(unique_ptr用)をセットにして追加。
        value_.push_back( make_pair( std::unique_ptr<void, void_deleter>(static_cast<void*>(new T(val)), [](void* p) { delete static_cast<T*>(p); }),const_cast<char*>( typeid(T).name() ) ));
    };
    /**
    * 登録したものをargsに参照渡し。
    * @param &args 色々な型データ.
    * @param int i 要素番号.
    */
    template <typename T>
    void get(T &args, int i = 0) {
        T* pdata = static_cast<T*>(value_[i].first.get());
        args = *pdata;
    }
    /**
    * 登録したデータの型名をchar*で返す。
    * @param int i 要素番号.
    * @return char* 要素名.
    */
    char* get_type(int i) {
        return  value_[i].second;
    }
};

使用例

MFC
//日本語を指定
setlocale(LC_ALL, "japanese");
std::unique_ptr<ObjectClass>data(new ObjectClass());
// input
int int_input(1);
char* char_input("hoge");
CString cstring_input("データ");
// 配列に追加
data->push_back(int_input);
data->push_back(char_input);
data->push_back(cstring_input);
// 比較用に別の内容に差し替え
int_input = 11;
char_input = "hogehoge";
cstring_input = "データデータ";
// 出力先
int int_output(-1);
char* char_output("char not found");
CString cstring_output("cstring not found");
// 出力
data->get(int_output);
data->get(char_output, 1);
data->get(cstring_output, 2);
// data->get(cstring_output, 0); //intデータをCStringへ移動しようとするのでエラー
// 表示
cout << "-----input-----" << endl;
cout << int_input << endl;
cout << char_input << endl;
cout << cstring_input << endl;
cout << "--CString--" << endl;
printf("%S\n", cstring_input);
cout << "-----output-----" << endl;
cout << int_output << endl;
cout << char_output << endl;
cout << cstring_output << endl;
cout << "--CString--" << endl;
printf("%S\n", cstring_output);
cout << "-----type-----" << endl;
cout << data->get_type(0) << endl;
cout << data->get_type(1) << endl;
cout << data->get_type(2) << endl;
// キー入力待ち
getchar();

スクリーンショット 2016-12-15 11.53.59.png

2
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1