我有一個小概念問題。我有不同的類代表邊的幾何數據,具體取決於它的邊緣類型。對於實施例的類的直線和一個圓:如何在一個變量中存儲不同的類?
class Line{
private:
double[3] startPoint;
double[3] endPoint;
public:
//getter and setter and some other functions such as equals
}
class Circle{
private:
double[3] center;
double[3] planeNormal;
double radius;
public:
//getter and setter and some other functions such as equals
}
現在我需要一個類Edge
存儲該邊緣和裝配幾何數據的類型。 最後邊緣必須存儲在std::vector<Edge> edges;
問題是,我不知道運行時的類型,因爲我正在分析CAD零件的邊界表示,它可以有不同類型的邊緣。
class Edge{
private:
EdgeType type;
GeometricData data;
public:
//...
}
所以,我應該如何設計我的class Edge
並具有存儲無論是Line
-object espacially GeometricData
,一個Circle
-object或其他幾何對象,這樣我就可以回去從GeometricData
到Line
,Circle
或什麼幾何類可能是。
- 我試圖多態性與
GeometricData
作爲基類,但衍生 類差異太大,因爲像B樣條曲線也 包括在內。 - 我也試過
GeometricData
作爲void*
併爲SET-並獲得-梅索德模板的方法 ,但我有,因爲壽命的對象的 (我的問題 存儲數據,而不是隻有指針,必須分析BRep遞歸)。
我也將理解,可以改變幾何表示的整個概念,只要建議,我可以使用edges
維矢量訪問類型擬合數據,諸如直線startPoint
或圓的radius
。編輯: 感謝您的快速回復。我決定使用suszterpatt的建議,包括我的一些模板,並在提到TAS時將我的std::vector<Edge>
更改爲std::vector<shared_ptr<Edge>>
。現在看起來像這樣:
#include "stdafx.h"
#include <string>
#include <sstream>
#include <iostream>
#include <vector>
using namespace std;
enum EdgeType{
LINE = 100,
CIRCLE
};
//Basis
class GeometricData {
private:
public:
virtual string toXMLString() = 0;
};
class Line : public GeometricData{
//less code just for illustration
private:
double d1;
public:
double getD1() { return d1; }
void setD1(double d1) { this->d1 = d1;}
virtual string toXMLString() {
stringstream s;
s << "d1=\"" << d1 <<"\"";
return s.str();
}
};
class Circle : public GeometricData{
private:
double d2;
public:
double getD2() { return d2; }
void setD2(double d2) { this->d2 = d2;}
virtual string toXMLString() {
stringstream s;
s << "d2=\"" << d2<<"\"";
return s.str();
}
};
class Edge{
private:
EdgeType t;
GeometricData* d;
public:
Edge() { d = 0;}
~Edge() {if (d) {delete d; d=0;}}
template <typename T> int setGeomData (T data) {
static_assert(
is_same<T,Line*>::value ||
is_same<T,Circle*>::value,
"EdgeGeometryType is not supported");
GeometricData* buffer = data;
//set type corresponding to thethis->data given= data
if(is_same<T,Line*>::value){
this->t = LINE;
Line* lb = dynamic_cast<Line*>(buffer);
Line* l = new Line(*lb);
this->d = l;
}else if (is_same<T,Circle*>::value){
this->t = CIRCLE;
Circle* cb = dynamic_cast<Circle*>(buffer);
Circle* c = new Circle(*cb);
this->d = c;
}else{// this case should not occure because of the static_assert
return -1;
}
return 0;
};
template <typename T> T getGeomData() {
static_assert(
is_same<T,Line*>::value ||
is_same<T,Circle*>::value,
"EdgeGeometryType is not supported");
if ((this->t == LINE && is_same<T,Line*>::value) ||
(this->t == CIRCLE && is_same<T,Circle*>::value))
{
return dynamic_cast<T>(this->d);
}else{
return NULL;
}
};
EdgeType getType(){ return t; }
//void setType(EdgeType t) { this->t = t; } not needed
GeometricData* getData(){return d;}
};
class Model {
private:
vector <shared_ptr<Edge>> edges;
public:
Model(){}
vector <shared_ptr<Edge>> getEdges(){ return edges; }
void addEdge (Edge* e) {edges.push_back(shared_ptr<Edge>(e));}
shared_ptr<Edge> getEdge(int i){ return edges.at(i); }
};
// Functions
void foo2 (Edge* e){
Line* l = new Line;
l->setD1(0.1);
e->setGeomData<Line*>(l);
//e->setType(LINE); not needed
delete l;
}
void foo1 (Edge* e){
Circle c;
c.setD2(0.2);
e->setGeomData<Circle*>(&c);
//e->setType(CIRCLE); not needed
}
void foo (Model* mdl){
Edge* e1 = new Edge;
Edge* e2 = new Edge;
foo1(e1);
foo2(e2);
mdl->addEdge(e1);
mdl->addEdge(e2);
}
int _tmain(int argc, _TCHAR* argv[])
{
Model mdl;
int i;
foo(&mdl);
cout << "Edge 1: " << mdl.getEdge(0)->getData()->toXMLString() << endl;
cout << "Edge 2: " << mdl.getEdge(1)->getData()->toXMLString() << endl;
for (i = 0; i<2; i++){
switch (mdl.getEdge(i)->getType()){
case LINE: {
Line* ld = (mdl.getEdge(i)->getGeomData<Line*>());
cout << "Line (templated get): " << ld->getD1() << endl;
}break;
case CIRCLE:{
Circle* cr = (mdl.getEdge(i)->getGeomData<Circle*>());
cout << "Circle (templated get): "<< cr->getD2() << endl;
}break;
}
}
return 0;
}
「我試過多態性,但派生類太不同了」。也許你的基類太具體了?這聽起來像是一個教科書的案例,在這個案例中,多樣性可以挽救一天:各種形狀如何不同? – suszterpatt
嗨suszterpatt, 我是相對多態概念的新手。也許我不正確地理解它。我認爲,如果我想從基礎派生到派生並返回,我需要在基類中派生類的每個方法的虛方法,並且每個派生類中必須實現每個虛方法。 如果我錯了,請糾正我,但是這不代表我的班級'Line'需要一個'getRadius()',因爲這必須是基於'GeometricData'的虛擬方法,因爲'Circle'需要這種方法? –
不是多態類的所有方法都需要是虛擬的。它的方式是,在基類中定義要在所有子類之間共享的常用方法,然後在子類中覆蓋基方法並定義該特定子類所需的其他方法。問題是,你的'Edge'類是否需要知道它正在操作的數據的確切類型?例如。它必須知道一個圓的半徑,或者'GeometricData'中的通用'getArea()'方法是否足夠,'Circle'可以使用該方法並使用其自己的半徑? – suszterpatt