I am porting an application from Windows to Linux. One component reads structured data from a file.
Sample Input: #10=CLOSED_POCKET(2.0, CARPET);
For every possible entity a corresponding c++ class is generated from the type definition. A factory creates the according object depending on the name of the entity (i.e CLOSED_POCKET). Afterwards the attributes are read one after another. Therefore we want to assign the members of the c++ class via the index of the current attribute.
The code works correctly on Windows compiled with Visual Studio 2010. I ported the code to Linux 10.04 (Lucid Lynx) and compiled it successfully with gcc 4.4.6 in Eclipse CDT Indigo.
Problem on Linux: When I access methods of the attributes the debugger sometimes jumps to wrong functions (resp. the function offset is not correct when function of subclasses should be called) what results in a segmentation fault.
I made a minimal example which also results in a segmentation fault (see below).
My Question is now: When Windows is able to run it successfully, what do I have to do, to run it under Linux with GCC?
I know that Downcasting virtual inherited classes is illegal according to the c++ standard (see Downcast in a diamond hierarchy ), but maybe there exists another solution to access members of instances via class scope. The virtual inheritance is needed because of the structure of the entities given from a ISO standard.
I also tought about providing an access array (MemberPtrArray) for every instance, but with about 80'000 entities read, an access over class scope would be nicer.
/*
* MemberPointerTest.h
*/
#ifndef MAINTEST_H_
#define MAINTEST_H_
#include <string>
class BaseAttribute{
public:
virtual void SetReal(double value);
virtual void SetSelectName(std::string selectName);
};
class RealAttribute : public BaseAttribute{
public:
double value;
virtual void SetReal(double value);
};
class SelectAttribute: public BaseAttribute{
public:
std::string selectName;
virtual void SetSelectName(std::string selectName);
};
class BaseEntity{
public:
BaseAttribute id;
virtual ~BaseEntity(){}
};
class PocketEntity : virtual public BaseEntity{
public:
RealAttribute depth;
};
class ClosedPocketEntity : virtual public PocketEntity{
public:
SelectAttribute surfaceType;
static BaseAttribute ClosedPocketEntity::* memberPtrArray[3];
BaseAttribute* GetMember(unsigned int index);
};
#endif
/*
* MemberPointerTest.cpp
*/
#include "MemberPointerTest.h"
void BaseAttribute::SetReal(double value){
}
void BaseAttribute::SetSelectName(std::string selectName){
}
void RealAttribute::SetReal(double value){
this->value = value;
}
void SelectAttribute::SetSelectName(std::string selectName){
this->selectName = selectName;
}
BaseAttribute ClosedPocketEntity::* ClosedPocketEntity::memberPtrArray[] = {
(BaseAttribute ClosedPocketEntity::*) &PocketEntity::depth,
(BaseAttribute ClosedPocketEntity::*) &ClosedPocketEntity::surfaceType
};
/* Tried the following alternatives:
* &PocketEntity::depth, // cannot convert ‘RealAttribute PocketEntity::*’ to ‘BaseAttribute ClosedPocketEntity::*’ in initialization
* (RealAttribute ClosedPocketEntity::*) &ClosedPocketEntity::depth, // invalid conversion from ‘RealAttribute ClosedPocketEntity::*’ to ‘BaseAttribute ClosedPocketEntity::*’
*/
BaseAttribute* ClosedPocketEntity::GetMember(unsigned int index){
return &(this->*memberPtrArray[index]);
}
int main(){
ClosedPocketEntity cpEntity;
// Case 1: Calls SetReal of BaseAttribute
BaseAttribute* depthPtr = cpEntity.GetMember(0);
depthPtr->SetReal(3.0);
// Case 2: Produces Segmentation fault
RealAttribute* depthPtr2 = dynamic_cast<RealAttribute*>(cpEntity.GetMember(0));
depthPtr2->SetReal(2.0); // SIGSEGV
return 0;
}