2014-09-21 5 views
3

다형성 객체의 크기를 가져오고 싶습니다. 이다다형성 객체의 크기 가져 오기

struct Base { 
    virtual std::size_t size() const { 
     return sizeof(*this); 
    } 
}; 

struct Derived : Base { 
    virtual std::size_t size() const { 
     return sizeof(*this); 
    } 
}; 

그대로 & 붙여 넣기를 복사 순간 나는이 있어요. 나는 더 잘하고 싶다. 매크로를 정말로 싫어하고 CRTP가 유일한 합리적인 접근 방법 인 것 같습니다. 우리가 한번 시도해 보자

struct SizedBase { 
    virtual std::size_t size() const = 0; 
}; 

template <typename Type> 
struct Sized : virtual SizedBase { 
    std::size_t size() const override { 
     return sizeof(Type); 
    } 
}; 

struct Base : Sized<Base> {}; 
struct Derived : Base, Sized<Derived> {}; 

이 훨씬 좋아 보이는,하지만 슬프게도 잘못 형성된다 : Derived최종 overriders Base에서 size()에 대한Sized<Derived>에서이 포함되어 있습니다. 우리는Sized을 통해 를 상속하여이 문제를 해결 할 수 있습니다

struct SizedBase { 
    virtual std::size_t size() const = 0; 
}; 

template <typename Type, typename... SizedBases> 
struct Sized : virtual SizedBase, SizedBases... { 
    std::size_t size() const override { 
     return sizeof(Type); 
    } 
}; 

struct Base : Sized<Base> {}; 
struct Derived : Sized<Derived, Base> {}; 

이 의도 한대로, 그러나 다중 상속의 경우에 다소 혼란 얻고 기지의 접근성/virtualness을 변경 금지 작동합니다.

그럼 더 좋은 방법이 있습니까?

+0

매크로는 여기에서했던 것보다 훨씬 깨끗하고 읽기 쉽습니다 ... – egur

+0

왜 크기가 필요합니까? –

+0

@ n.m. 할당 된 블록의 크기를 저장하지 않고 할당 해제시 명시 적으로 제공해야하는 사용자 정의 메모리 할당자를 위해. 그러나이 문제는 유형 이름 ('type_info :: name()'이 깨진 것처럼) 또는'clone (와 같은 것)과 같은 어떤 다른 다형성 (polymorphic type) 속성 ('typeid'를 통해 얻을 수있는))'복사 생성자를 통해 정의됩니다. –

답변

1
사람이 정말이 사용하도록

아니,하지만 ...

template <typename> 
struct None1 {}; 
template <typename> 
struct None2 {}; 

template <typename T> 
struct PrivateBase { using Tpriv = T; using Tprot = None1<T>; using Tpub = None2<T>; }; 
template <typename T> 
struct ProtectedBase { using Tpriv = None1<T>; using Tprot = T; using Tpub = None2<T>; }; 
template <typename T> 
struct PublicBase { using Tpriv = None1<T>; using Tprot = None2<T>; using Tpub = T; }; 

template <typename K> 
struct TriBase : private K::Tpriv, protected K::Tprot, public K::Tpub {}; 

template <typename T, typename ... Bases> 
struct Sized : private Bases::Tpriv..., protected Bases::Tprot..., public Bases::Tpub... 
{ 
    virtual size_t size() { return sizeof(T); } 
}; 


struct Foo : Sized<Foo> {}; 

struct X{}; 
struct Y{}; 

struct Bar : Sized<Bar, PrivateBase<X>, ProtectedBase<Y>, PublicBase<Foo>> {}; 

int main() 
{ 
    Bar b; 
    Foo* f = &b; 
    X* x = &b; // error : private base 
    Y* y = &b; // error : protected base 
} 

가상 상속은 독자에게 연습으로 남아 있습니다.

기본 클래스의 순서는 유지되지 않지만 어쨌든 그것에 종속되지 않아야합니다. 물론 하나의

#include <cstdlib> 
#include <typeinfo> 
#include <unordered_map> 
#include <memory> 
#include <iostream> 

struct myinfo 
{ 
    size_t size; 
    // any other stuff 
}; 

using TypeInfoRef = std::reference_wrapper<const std::type_info>; 
struct Hasher 
{ 
    std::size_t operator()(TypeInfoRef code) const 
    { 
     return code.get().hash_code(); 
    } 
}; 

struct EqualTo 
{ 
    bool operator()(TypeInfoRef lhs, TypeInfoRef rhs) const 
    { 
     return lhs.get() == rhs.get(); 
    } 
}; 

static std::unordered_map<TypeInfoRef, myinfo, Hasher, EqualTo> typemap; 

template <typename K> 
struct typemap_initializer 
{ 
    typemap_initializer() 
    { 
     typemap[typeid(K)] = myinfo{sizeof(K)}; 
    } 
}; 

struct Base 
{ 
    virtual ~Base() {} 
    size_t size() { return typemap[typeid(*this)].size; } 
    template<typename K, typename... Arg> 
     friend K* alloc(Arg...); 
    private: 
    void* operator new(size_t sz) { return ::operator new(sz); } 
}; 

    template<typename K, typename... Arg> 
K* alloc(Arg... arg) 
{ 
    static typemap_initializer<K> ti; 
    return new K(arg...); 
} 

struct Foo : Base {int a;}; 
struct Bar : Foo {int b; int c;}; 

int main() 
{ 
    Foo* f = alloc<Foo>(); 
    Bar* g = alloc<Bar>(); 

    std::cout << f->size() << std::endl; 
    std::cout << g->size() << std::endl; 
} 

친숙한 Foo* foo = new Foo 구문을 제공하지만, 유비쿼터스의 시대 : 조금 더 생산하기 쉬운

뭔가 (이 거친 스케치입니다)이 다음과 같이 구현 될 수있다 std::make_shared<> 큰 문제는 아닙니다.

+0

니스, 이것 생각하지 않았어. 그러나 개인은 여기에서 부러집니다 : 사적 기지는'Sized <>'에게 사적인 것입니다. 그들이 접근 할 수없는'Bar'가 아닙니다. –

+0

예, 개인적으로 템플릿을 통해 "상속하는"것은 불가능합니다. 신경 쓰지 마라, 나는 덜 끔찍한 것으로 업데이트했다. –

+0

* 제작 용이 * 버전은 유감스럽게도 멀티 스레딩이 쉽지 않습니다. 잠금을 추가하는 것은 사소한 일입니다. –