将不同类型的指针存储在一个数组中
Store pointers of different type in one array
我想在一个数据结构(例如数组、HashMap ...)中存储指向不同 classes 的对象的指针。根据 this answer,我得出以下解决方案,使用无类型指针 void*
和运算符 &*( ClassName* )
进行指针类型重铸:
#include <stdio.h>
class ClassA{ public: int a; };
class ClassB{ public: double b; };
class Storage{
public:
int n;
void** store;
Storage( int n_ ){ n = n_; store = new void*[n]; };
};
Storage s( 5 );
int main(){
// test store and load ClassA
ClassA a1; a1.a = 16;
s.store[ 0 ] = &a1;
ClassA* a2 = &*( ClassA* ) s.store[ 0 ];
printf( " a2 %i \n", a2->a );
// test store and load ClassB
ClassB b1; b1.b = 15.1455;
s.store[ 1 ] = &b1;
ClassB* b2 = &*( ClassB* ) s.store[ 1 ];
printf( " b2 %f \n", b2->b );
}
现在问题:
- 除了类型不安全之外,像
&*( ClassB* )
这样的类型转换有什么不好的吗?
- 此类型转换是否有任何性能成本?
- 有没有更好(更好、更安全、更快)的方法来将指向不同 class 的不同对象的指针存储在单个数组中?
啊,我发现它实际上是没有用的 void**
因为我现在知道以后如何识别存储对象的类型。更好的做法是使用模板和普通超级 class。像这样
#include <stdio.h>
#include <cstdlib>
template< class TYPE1 > class Storage{
public:
int n;
TYPE1** store;
Storage( int n_ ){ n = n_; store = new TYPE1*[n]; }; // Constructor
void put( int key, TYPE1* obj ){ store[key] = obj; }; // save data
TYPE1* get( int key ){ return store[key]; }; // load data
};
class Parent { public: int kind; };
class ChildA : public Parent { public: int someData; ChildA( int someData_ ){ kind=0; someData =someData_; } };
class ChildB : public Parent { public: double otherData; ChildB( double otherData_ ){ kind=1; otherData=otherData_; } };
Storage<Parent> mixed( 10 );
int main(){
srand( 15454 );
printf( " ==== initialize by random data and radom type \n" );
for(int i=0; i<mixed.n; i++ ){
if ( (rand()&4) > 0 ){
int someData = rand()&0xFF;
mixed.put( i, new ChildA( someData ) );
printf( " i %i ChildA.someData = %i \n", i , someData );
}else{
double otherData = (rand()&0xFF)/256.0f;
mixed.put( i, new ChildB( otherData ) );
printf( " i %i ChildB.otherData = %f \n", i , otherData );
};
};
printf( " ==== recall stored data \n" );
for(int i=0; i<mixed.n; i++ ){
Parent* obj = mixed.get( i );
if ( obj->kind ==0 ){ printf( " i %i ChildA.someData = %i \n", i , ( (ChildA *) obj )->someData ); }
else { printf( " i %i ChildB.otherData = %f \n", i , ( (ChildB *) obj )->otherData ); };
};
}
Is anything bad about typecasting like &*( ClassB* )
except that it is not type safe?
将 *
后跟 &
应用于指针是空操作,因此只需 (ClassB*)
就足够了。此外,您应该使用 C++ 风格的转换,在本例中 static_cast<ClassB*>
,而不是 C 风格的转换,以使您的意思更加明确。
糟糕的是,这不仅不是类型安全的,而且非常混乱,是对 C++ 语言的滥用。
Is there any performance cost for this typecasting ?
没有
Is there any better ( nicer, more safe, faster ) way how store pointer to different objects of different class in a single array?
是的,最好的方法是将这些类型的常见行为分解为基数 class(可能是抽象的),并声明数组以存储指向该基数 class 的指针。如果没有共同的行为,那么将它们全部存储在同一个数组中几乎总是错误的做法。如果出于某种原因您真的想这样做,Boost.Any 之类的方法可能是正确的解决方案。
我想在一个数据结构(例如数组、HashMap ...)中存储指向不同 classes 的对象的指针。根据 this answer,我得出以下解决方案,使用无类型指针 void*
和运算符 &*( ClassName* )
进行指针类型重铸:
#include <stdio.h>
class ClassA{ public: int a; };
class ClassB{ public: double b; };
class Storage{
public:
int n;
void** store;
Storage( int n_ ){ n = n_; store = new void*[n]; };
};
Storage s( 5 );
int main(){
// test store and load ClassA
ClassA a1; a1.a = 16;
s.store[ 0 ] = &a1;
ClassA* a2 = &*( ClassA* ) s.store[ 0 ];
printf( " a2 %i \n", a2->a );
// test store and load ClassB
ClassB b1; b1.b = 15.1455;
s.store[ 1 ] = &b1;
ClassB* b2 = &*( ClassB* ) s.store[ 1 ];
printf( " b2 %f \n", b2->b );
}
现在问题:
- 除了类型不安全之外,像
&*( ClassB* )
这样的类型转换有什么不好的吗? - 此类型转换是否有任何性能成本?
- 有没有更好(更好、更安全、更快)的方法来将指向不同 class 的不同对象的指针存储在单个数组中?
啊,我发现它实际上是没有用的 void**
因为我现在知道以后如何识别存储对象的类型。更好的做法是使用模板和普通超级 class。像这样
#include <stdio.h>
#include <cstdlib>
template< class TYPE1 > class Storage{
public:
int n;
TYPE1** store;
Storage( int n_ ){ n = n_; store = new TYPE1*[n]; }; // Constructor
void put( int key, TYPE1* obj ){ store[key] = obj; }; // save data
TYPE1* get( int key ){ return store[key]; }; // load data
};
class Parent { public: int kind; };
class ChildA : public Parent { public: int someData; ChildA( int someData_ ){ kind=0; someData =someData_; } };
class ChildB : public Parent { public: double otherData; ChildB( double otherData_ ){ kind=1; otherData=otherData_; } };
Storage<Parent> mixed( 10 );
int main(){
srand( 15454 );
printf( " ==== initialize by random data and radom type \n" );
for(int i=0; i<mixed.n; i++ ){
if ( (rand()&4) > 0 ){
int someData = rand()&0xFF;
mixed.put( i, new ChildA( someData ) );
printf( " i %i ChildA.someData = %i \n", i , someData );
}else{
double otherData = (rand()&0xFF)/256.0f;
mixed.put( i, new ChildB( otherData ) );
printf( " i %i ChildB.otherData = %f \n", i , otherData );
};
};
printf( " ==== recall stored data \n" );
for(int i=0; i<mixed.n; i++ ){
Parent* obj = mixed.get( i );
if ( obj->kind ==0 ){ printf( " i %i ChildA.someData = %i \n", i , ( (ChildA *) obj )->someData ); }
else { printf( " i %i ChildB.otherData = %f \n", i , ( (ChildB *) obj )->otherData ); };
};
}
Is anything bad about typecasting like
&*( ClassB* )
except that it is not type safe?
将 *
后跟 &
应用于指针是空操作,因此只需 (ClassB*)
就足够了。此外,您应该使用 C++ 风格的转换,在本例中 static_cast<ClassB*>
,而不是 C 风格的转换,以使您的意思更加明确。
糟糕的是,这不仅不是类型安全的,而且非常混乱,是对 C++ 语言的滥用。
Is there any performance cost for this typecasting ?
没有
Is there any better ( nicer, more safe, faster ) way how store pointer to different objects of different class in a single array?
是的,最好的方法是将这些类型的常见行为分解为基数 class(可能是抽象的),并声明数组以存储指向该基数 class 的指针。如果没有共同的行为,那么将它们全部存储在同一个数组中几乎总是错误的做法。如果出于某种原因您真的想这样做,Boost.Any 之类的方法可能是正确的解决方案。