다형성 C ++ 클래스의 크기 결정
-
05-07-2019 - |
문제
사용 sizeof
연산자, 모든 유형의 크기를 결정할 수 있지만 런타임에 다형성 클래스의 크기를 어떻게 동적으로 결정할 수 있습니까?
예를 들어, 나는에 대한 포인터가 있습니다 Animal
, 그리고 나는 그것이 가리키는 실제 객체의 크기를 얻고 싶습니다. Cat
또는 a Dog
. 가상 메소드를 만드는 것이 부족한 간단한 방법이 있습니까? Animal::size
그리고 그것을 반환하기 위해 그것을 과부하 시키십시오 sizeof
각 특정 유형의?
해결책
가능한 유형 세트를 알고 있다면 RTTI를 사용하여 수행하여 동적 유형을 찾을 수 있습니다. dynamic_cast
. 그렇지 않으면 유일한 방법은 가상 기능을 사용하는 것입니다.
다른 팁
또는 dynamic_cast보다 빠를 수있는 TypeId를 사용할 수 있습니다 (Dynamic_cast를 사용하면 계층 구조에서 중개자 유형으로 캐스트 할 수 있음).
다소 나쁘게 보입니다.
#include <iostream>
#include <typeinfo>
class Creature
{
char x[4];
public:
virtual ~Creature() {}
};
class Animal: public Creature { char x[8];};
class Bird: public Creature { char x[16]; };
class Dog: public Animal { char x[32]; };
class Cat: public Animal { char x[64]; };
class Parrot: public Bird { char x[128]; };
unsigned creature_size(const Creature& cr)
{
if (typeid(cr) == typeid(Animal)) {
return sizeof (Animal);
}
else if (typeid(cr) == typeid(Dog)) {
return sizeof(Dog);
}
else if (typeid(cr) == typeid(Cat)) {
return sizeof(Cat);
}
else if (typeid(cr) == typeid(Bird)) {
return sizeof(Bird);
}
else if (typeid(cr) == typeid(Parrot)) {
return sizeof(Parrot);
}
else if (typeid(cr) == typeid(Creature)){
return sizeof(Creature);
}
assert(false && "creature_size not implemented for this type");
return 0;
}
int main()
{
std::cout << creature_size(Creature()) << '\n'
<< creature_size(Animal()) << '\n'
<< creature_size(Bird()) << '\n'
<< creature_size(Dog()) << '\n'
<< creature_size(Cat()) << '\n'
<< creature_size(Parrot()) << '\n' ;
}
각각의 새로운 유형마다 creature_size 함수에 코드를 추가해야합니다. 가상 크기 기능을 사용하면 각 클래스 에서도이 기능을 구현해야합니다. 그러나이 기능은 상당히 단순해질 것입니다 (완벽하게 Copy-N Pastable, 이는 언어의 한계와 코드 설계 문제가있을 수 있음을 보여줍니다).
virtual unsigned size() const { return sizeof(*this); }
기본 클래스에서 추상화 할 수 있습니다. 즉,이 메소드를 무시하는 것을 잊어 버린 경우 컴파일러 오류가 될 수 있습니다.
편집 : 이것은 자연스럽게 그 크기를 알고 싶은 생물을 주어야한다고 가정합니다. 개를 다루고 있다고 믿을만한 강한 이유가 있다면 - 개의 서브 클래스 (그리고 서브 클래스인지 상관하지 않음) 자연스럽게 Dynamic_cast를 사용할 수 있습니다. 애드 혹 테스트.
소스 클래스의 디자인을 변경할 수 있다면 동적 다형성 (가상 함수를 사용하는)을 정적 다형성으로 완전히 대체하고 CRTP 관용구:
template <class TDerived>
class Base
{
public:
int getSize()
{ return sizeof(TDerived); }
void print()
{
std::cout
<< static_cast<TDerived*>(this)->getSize()
<< std::endl;
}
int some_data;
};
class Derived : public Base<Derived>
{
public:
int some_other_data1;
int some_other_data2;
};
class AnotherDerived : public Base<AnotherDerived>
{
public:
int getSize()
{ return some_unusual_calculations(); }
// Note that the static_cast above is required for this override to work,
// because we are not using virtual functions
};
int main()
{
Derived d;
d.print();
AnotherDerived ad;
ad.print();
return 0;
}
필요할 때이를 수행 할 수 있습니다 다형성 행동 프로그램의 프로그램을 컴파일 타임으로 결정할 수 있습니다 (예 : sizeof
CASE), CRTP는 런타임에 원하는 대상을 해결하기 위해 동적 다형성의 유연성이 없기 때문에.
정적 다형성은 또한 가상 기능 통신 오버 헤드를 제거함으로써 더 높은 성능의 이점을 가지고 있습니다.
기본 클래스를 템플릿으로 템플릿을 만들고 싶지 않거나 동일한 위치 (배열 또는 벡터와 같은)에서 다른 파생 된 기본 클래스 인스턴스를 보유 해야하는 경우 중산층에서 CRTP를 사용하여 다형성 동작을 해당 클래스로 이동할 수 있습니다. (와 유사합니다 다형성 사본 구성 예 위키 백과에서) :
class Base
{
public:
virtual int getSize() = 0;
void print()
{
std::cout << getSize() << std:endl;
}
int some_data;
};
template <class TDerived>
class BaseCRTP: public Base
{
public:
virtual int getSize()
{ return sizeof(TDerived); }
};
class Derived : public BaseCRTP<Derived>
{
// As before ...
};
class AnotherDerived : public BaseCRTP<AnotherDerived>
{
// As before ...
// Note that although no static_cast is used in print(),
// the getSize() override still works due to virtual function.
};
Base* obj_list1[100];
obj_list1[0] = new Derived();
obj_list1[2] = new AnotherDerived();
std::vector<Base*> obj_list2;
obj_list2.push_back(new Derived());
obj_list2.push_back(new AnotherDerived());
--
업데이트: 나는 이제 비슷하지만 더 상세한 것을 발견했습니다 대답 Stackoverflow에서 위의 파생 클래스에서 더 파생된다면 (예 : class FurtherDerived : public Derived {...}
), sizeof
올바르게보고하지 않습니다. 그는 a 더 복잡한 변형 이것을 극복하기위한 코드의.
나는 누군가가 적절한 특성을 구현하는 대신 발명 된 type_id ()를 믿을 수 없다 ....