Методы стирания типа

(Под стиранием типа я подразумеваю скрытие некоторой или всей информации о типе, относящейся к классу, что-то вроде Boost. Any .)
Я хочу овладеть методами стирания шрифтов, а также поделиться теми, о которых я знаю. Я надеюсь найти какую-то безумную технику, о которой кто-то подумал в самый темный час. :)

Первый, наиболее очевидный и распространенный подход, который я знаю, - это виртуальные функции. Просто скройте реализацию вашего класса внутри иерархии классов на основе интерфейса. Многие библиотеки Boost делают это, например Boost.Any делает это, чтобы скрыть ваш тип, а Boost.Shared_ptr делает это, чтобы скрыть механизм (де) распределения.

Затем есть вариант с указателями функций на шаблонные функции, при сохранении фактического объекта в указателе void * , как, например, Boost.Function , чтобы скрыть реальный тип объекта функтор. Примеры реализации можно найти в конце вопроса.

Итак, на мой актуальный вопрос:
Какие еще техники стирания типа вам известны? Пожалуйста, предоставьте им, если возможно, пример кода, варианты использования, ваш опыт работы с ними и, возможно, ссылки для дальнейшего чтения.

Изменить
(Поскольку я не был уверен, что добавлю это в качестве ответа или просто отредактируйте вопрос, я просто сделаю более безопасный.)
Другой хороший способ скрыть реальный тип чего-то без виртуальных функций или void * возни, GMan применяет здесь , имеющий отношение к my вопрос о том, как именно это работает.


Пример кода:

#include 
#include 

// NOTE: The class name indicates the underlying type erasure technique

// this behaves like the Boost.Any type w.r.t. implementation details
class Any_Virtual{
        struct holder_base{
                virtual ~holder_base(){}
                virtual holder_base* clone() const = 0;
        };

        template
        struct holder : holder_base{
                holder()
                        : held_()
                {}

                holder(T const& t)
                        : held_(t)
                {}

                virtual ~holder(){
                }

                virtual holder_base* clone() const {
                        return new holder(*this);
                }

                T held_;
        };

public:
        Any_Virtual()
                : storage_(0)
        {}

        Any_Virtual(Any_Virtual const& other)
                : storage_(other.storage_->clone())
        {}

        template
        Any_Virtual(T const& t)
                : storage_(new holder(t))
        {}

        ~Any_Virtual(){
                Clear();
        }

        Any_Virtual& operator=(Any_Virtual const& other){
                Clear();
                storage_ = other.storage_->clone();
                return *this;
        }

        template
        Any_Virtual& operator=(T const& t){
                Clear();
                storage_ = new holder(t);
                return *this;
        }

        void Clear(){
                if(storage_)
                        delete storage_;
        }

        template
        T& As(){
                return static_cast*>(storage_)->held_;
        }

private:
        holder_base* storage_;
};

// the following demonstrates the use of void pointers 
// and function pointers to templated operate functions
// to safely hide the type

enum Operation{
        CopyTag,
        DeleteTag
};

template
void Operate(void*const& in, void*& out, Operation op){
        switch(op){
        case CopyTag:
                out = new T(*static_cast(in));
                return;
        case DeleteTag:
                delete static_cast(out);
        }
}

class Any_VoidPtr{
public:
        Any_VoidPtr()
                : object_(0)
                , operate_(0)
        {}

        Any_VoidPtr(Any_VoidPtr const& other)
                : object_(0)
                , operate_(other.operate_)
        {
                if(other.object_)
                        operate_(other.object_, object_, CopyTag);
        }

        template
        Any_VoidPtr(T const& t)
                : object_(new T(t))
                , operate_(&Operate)
        {}

        ~Any_VoidPtr(){
                Clear();
        }

        Any_VoidPtr& operator=(Any_VoidPtr const& other){
                Clear();
                operate_ = other.operate_;
                operate_(other.object_, object_, CopyTag);
                return *this;
        }

        template
        Any_VoidPtr& operator=(T const& t){
                Clear();
                object_ = new T(t);
                operate_ = &Operate;
                return *this;
        }

        void Clear(){
                if(object_)
                        operate_(0,object_,DeleteTag);
                object_ = 0;
        }

        template
        T& As(){
                return *static_cast(object_);
        }

private:
        typedef void (*OperateFunc)(void*const&,void*&,Operation);

        void* object_;
        OperateFunc operate_;
};

int main(){
        Any_Virtual a = 6;
        std::cout << a.As() << std::endl;

        a = std::string("oh hi!");
        std::cout << a.As() << std::endl;

        Any_Virtual av2 = a;

        Any_VoidPtr a2 = 42;
        std::cout << a2.As() << std::endl;

        Any_VoidPtr a3 = a.As();
        a2 = a3;
        a2.As() += " - again!";
        std::cout << "a2: " << a2.As() << std::endl;
        std::cout << "a3: " << a3.As() << std::endl;

        a3 = a;
        a3.As().As() += " - and yet again!!";
        std::cout << "a: " << a.As() << std::endl;
        std::cout << "a3->a: " << a3.As().As() << std::endl;

        std::cin.get();
}

129
задан Community 23 May 2017 в 11:54
поделиться