Использование этого в отдельных методах класса приводит к сбою программы - PullRequest
0 голосов
/ 04 апреля 2020

У меня есть вызов вызова методов из прямого родительского базового класса, но я могу с легкостью вызывать методы в родительском базовом классе. Чтобы прояснить, что я имею в виду, вот код:

Сначала структура классов библиотеки opencascade:

class TopoDS_Shape 
{
public:
   //..... a lot of methods like Closed(), Oriantable(), etc
};

class TopoDS_Face : public TopoDS_Shape
{
   TopoDS_Face(); // implementation is like TopoDS_Face::TopoDS_Face(){}
}

В моем коде есть два типа топологических граней Плоские грани (класс ModelFace) и неплоские грани (класс ModelBend). Эти две грани имеют 6 общих атрибутов, определенных в классе MFace, но только класс ModelBend имеет свои собственные дополнительные атрибуты, поэтому я спроектировал систему следующим образом:

Класс MFace:

class MFace : public TopoDS_Face 
{
 FaceID mFaceID;
 PlaneType mPlaneType;
 FaceType mFaceType;
 gp_Pnt mFaceNormal;

 public:
  void ModelFace::extractEdges()
  {
    for (TopExp_Explorer edgeEx((*this), TopAbs_EDGE); edgeEx.More(); edgeEx.Next())
    {
      TopoDS_Edge edge = TopoDS::Edge(edgeEx.Current());
      ModelEdge edgex(edge);

      addEdge(edgex);
    }
  }

  // Setters and getters

  // The OpenCascade Lib has a non-template method similar to this for converting a  
  // TopoDS_Shape to a face/edge/vertex/wire
  template<typename T>
  static T& toFace(TopoDS_Face& shape)
  {
    return *(T*) &shape;
   }
};

Класс ModelFace:

 class ModelFace : public MFace
 {
   ModelFace(); // implementation is like ModelFace::ModelFace(){}

   void ModelFace::init(FaceID faceID) // WORKS LIKE A CHARM!!!
   { 
     setFaceId(faceID);

     std::cout << "ID : " << getFaceId() << '\n';

     if (Closed()) {
      std::cout << "Orr : " << Orientable() << '\n';
     }
   }

 };

Класс ModelBend:

class ModelBend : public MFace
 {
   // Bend attributes : angles, radius, etc
   ModelBend(); // implementation is like ModelBend::ModelBend(){}

   // Setters and getters
   // methods for computations

};

Использование: существует класс Model, который представляет модель CAD и хранит все ее топологические данные ModelFace / ModelBend. Этот класс получает топологические данные в виде TopoDS_Shape и классифицирует их в assignAttributes(), как показано ниже:

  void Model::assignFaceAttributes(const FaceID faceID, TopoDS_Shape& aShape)
  {
    // TODO : set the face attributes
    TopoDS_Face pTopoDSFace = TopoDS::Face(aShape);
    Standard_Real curvature = computeCurvature(pTopoDSFace);

    if (curvature == 0.0){

      std::cout << "Face" << '\n';

      // Convert TopoDS_Face to ModelFace
      ModelFace& pModelFace = MFace::toFace<ModelFace>(pTopoDSFace);

      // This code work well : calls Orientable() in the TopoDS_Shape class
      std::cout << "Orientable? : " << pModelFace.Orientable() << '\n';

      // Works well
      pModelFace.init(faceID);

      // **PROGRAM CRASHES HERE!!!!!!!!!!!!!!**
      pModelFace.extractEdges();

      //...

    } else {
      // .....
      std::cout << "Bend" << '\n';

      // Convert TopoDS_Face to ModelBend
      ModelBend& pModelFace = MFace::toFace<ModelBend>(pTopoDSFace);

      //...
    }

    addFace(&pModelFace);

  }

При запуске программы происходит сбой при вызове pModelFace.extractEdges() в assignAttributes() но когда я копирую для l oop в методе extractEdges() в метод init(), он работает нормально.

Мой OOD / OOP не так хорош. Можете ли вы помочь мне решить проблему и причины этого поведения. Заранее спасибо.

1 Ответ

1 голос
/ 04 апреля 2020

Это похоже на дубликат вашего собственного вопроса: Назначение объекта TopoDS_Face его дочернему объекту компилируется без ошибок, но у меня есть 3 ошибки valgrind

TopoDS_Shape имеет нет виртуальных методов (включая виртуальный деструктор) и управляется в OCCT копией (например, динамически не распределяется). Добавление полей класса, как вы делаете в MFace, будет работать только в том случае, если вы сохраняете объект точно так же, как MFace - в противном случае вы просто приводите меньший в памяти объект TopoDS_Shape к большему MFace, что приводит к чтению / записи неинициализированным память и cra sh.

Основное различие между вашими MFace и TopoDS_Face состоит в том, что TopoDS_Face определяет НЕТ новых полей класса или виртуальных методов, что позволяет создавать псевдонимы TopoDS_Shape до TopoDS_Face без побочных эффектов.

Например:

void parseMFace (TopoDS_Shape& theFace)
{
  MFace* anMFace = (MFace* )&theFace;
  anMFace->doSomething();
}

int main()
{
  MFace anMFace;
  parseMFace (anMFace); // unsafe, but should work
  TopoDS_Face aTFace;
  parseMFace (aTFace); // will crash
  TopoDS_Compound aComp;
  BRep_Builder().MakeCompound (aComp);
  BRep_Builder().Add (aComp, anMFace); // here MFace will be truncated to TopoDS_Shape
  for (TopoDS_Iterator aFaceIter (aComp); aFaceIter.More(); aFaceIter.Next()
  {
    TopoDS_Face& aTFace2 = TopoDS::Face (aFaceIter.Value());
    parseMFace (aTFace2); // will crash, because TopoDS_Compound does not store MFace 
  }
  std::vector<MFace> anMFaces;
  anMFaces.push_back (anMFace);
  parseMFace (anMFaces[0]); // OK, but unsafe
}
...