(유형 삭제를 사용하면 Boost.Any 와 같은 클래스에 대한 유형 정보의 일부 또는 전부를 숨기는 것을 의미합니다 .)
유형 삭제 기술을 유지하면서 알고있는 기술을 공유하고 싶습니다. 누군가가 자신의 가장 어두운 시간에 생각했던 미친 기술을 찾기를 바랍니다. :)
내가 아는 첫 번째이자 가장 명백하고 일반적으로 사용되는 접근 방식은 가상 기능입니다. 인터페이스 기반 클래스 계층 구조에서 클래스 구현을 숨기십시오. 많은 Boost 라이브러리가 이것을 수행합니다 (예 : Boost.Any 는 유형을 숨기고 이를 수행 하며 Boost.Shared_ptr 은 (de) 할당 메커니즘을 숨기려고합니다).
그런 다음 템플릿과 같은 함수 포인터가있는 옵션이 있으며 Boostvoid*
와 같은 포인터에 실제 객체를 보유하고 함수 는 실제 유형의 functor를 숨 깁니다. 질문의 끝에 구현 예를 찾을 수 있습니다.
내 실제 질문에 대해,
당신은 다른 어떤 유형의 삭제 기술을 알고 있습니까? 가능한 경우 예제 코드, 사용 사례, 경험 및 추가 정보를 제공하는 링크를 제공하십시오.
편집
(이 답변을 추가하거나 질문을 편집하는 것이 확실하지 않기 때문에 더 안전한
방법을 사용 하겠습니다.) 가상 기능이나 방해 없이 실제 유형의 물건을 숨기는 또 다른 좋은 기술 void*
은 하나의 GMan이 여기 에 어떻게 작동하는지에 대한 나의 질문 과 관련하여 고용 합니다.
예제 코드 :
#include <iostream>
#include <string>
// 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<class T>
struct holder : holder_base{
holder()
: held_()
{}
holder(T const& t)
: held_(t)
{}
virtual ~holder(){
}
virtual holder_base* clone() const {
return new holder<T>(*this);
}
T held_;
};
public:
Any_Virtual()
: storage_(0)
{}
Any_Virtual(Any_Virtual const& other)
: storage_(other.storage_->clone())
{}
template<class T>
Any_Virtual(T const& t)
: storage_(new holder<T>(t))
{}
~Any_Virtual(){
Clear();
}
Any_Virtual& operator=(Any_Virtual const& other){
Clear();
storage_ = other.storage_->clone();
return *this;
}
template<class T>
Any_Virtual& operator=(T const& t){
Clear();
storage_ = new holder<T>(t);
return *this;
}
void Clear(){
if(storage_)
delete storage_;
}
template<class T>
T& As(){
return static_cast<holder<T>*>(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<class T>
void Operate(void*const& in, void*& out, Operation op){
switch(op){
case CopyTag:
out = new T(*static_cast<T*>(in));
return;
case DeleteTag:
delete static_cast<T*>(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<class T>
Any_VoidPtr(T const& t)
: object_(new T(t))
, operate_(&Operate<T>)
{}
~Any_VoidPtr(){
Clear();
}
Any_VoidPtr& operator=(Any_VoidPtr const& other){
Clear();
operate_ = other.operate_;
operate_(other.object_, object_, CopyTag);
return *this;
}
template<class T>
Any_VoidPtr& operator=(T const& t){
Clear();
object_ = new T(t);
operate_ = &Operate<T>;
return *this;
}
void Clear(){
if(object_)
operate_(0,object_,DeleteTag);
object_ = 0;
}
template<class T>
T& As(){
return *static_cast<T*>(object_);
}
private:
typedef void (*OperateFunc)(void*const&,void*&,Operation);
void* object_;
OperateFunc operate_;
};
int main(){
Any_Virtual a = 6;
std::cout << a.As<int>() << std::endl;
a = std::string("oh hi!");
std::cout << a.As<std::string>() << std::endl;
Any_Virtual av2 = a;
Any_VoidPtr a2 = 42;
std::cout << a2.As<int>() << std::endl;
Any_VoidPtr a3 = a.As<std::string>();
a2 = a3;
a2.As<std::string>() += " - again!";
std::cout << "a2: " << a2.As<std::string>() << std::endl;
std::cout << "a3: " << a3.As<std::string>() << std::endl;
a3 = a;
a3.As<Any_Virtual>().As<std::string>() += " - and yet again!!";
std::cout << "a: " << a.As<std::string>() << std::endl;
std::cout << "a3->a: " << a3.As<Any_Virtual>().As<std::string>() << std::endl;
std::cin.get();
}
shared_ptr
이를 반영하지 않으며 shared_ptr<int>
표준 컨테이너와 달리 항상 동일 합니다.
As
(들) 함수는 그런 식으로 구현되지 않습니다. 내가 말했듯이, 결코 안전한 것은 아닙니다! :)
function
, shared_ptr
, any
, 등? 그들은 모두 달콤한 달콤한 사용자 편의를 위해 유형 삭제를 사용합니다.