2017-07-02 86 views
0

對於noob問題抱歉,但我似乎無法擺脫C++的靜態性質。問題:我有一個返回一個枚舉的類,根據它我必須使用另一個類來轉換所述類並返回一個向量。在代碼:取決於枚舉的函數超載

enum TYPES { TYPE_A, TYPE_B, TYPE C } 

class A { 
    TYPES getType() {} 
} 
class B : public A {} 
class C : public A {} 
class D : public A {} 

std::vector<?> convert_to_vector(const A& a) { 
    // depending on what enum is returned by a.getType() 
    // I have to convert a into B, C, or D class and return std::vector of 
    // an appropriate type, e.g. int for B, float for C, etc. 
} 

int main() { 
    A a; 
    auto v = convert_to_vector(a); 
} 

最簡單的方法將使用switch(a.getType())但我在各種情況下具有不同的返回類型和使用auto返回類型不起作用。我已經嘗試過模板和模板規範,但他們不接受由a.getType()返回的運行時變量。我想在這裏我必須有一些簡單的解決方案,但我在這一點上已經沒有想法,並且會很感激任何指針。

謝謝!

+2

你想用這個解決方案解決什麼問題?你不能使用虛函數,多態性和指向基類的指針嗎?一般來說,打開「類型」往往是一個糟糕的設計的標誌。 –

+0

那麼,我正在使用一個庫給我所有的類和枚舉。正如我所說的,基類「A」通過該函數只告訴我它的類型,我必須將它轉換爲派生類來獲取向量所需的數據。我想創建一個由enum專門開發的派生類,但C++不是我的母語,我很快就迷失在模板中。 – maga

回答

2

您不能在運行時更改C++函數的返回類型。但是你可以使用一個variant類型:

std::variant<std::vector<int>, std::vector<float>> convert_to_vector(const A& a) { 
    if (a.getType() == TYPE_B) 
     return std::vector<int>(); 
    if (a.getType() == TYPE_C) 
     return std::vector<float>(); 
    throw std::logic_error("unsupported type"); 
} 

如果你沒有C++ 17,你可以用boost::variant而不是std::variant

1

我認爲,而不是決定一個枚舉上的向量的類型一個更好的解決方案將是有一個父母class A其中可以有一個向量內的基於模板變量。在您的課程B, C, D中,您可以簡單地繼承A並指定模板類型。所以,當你爲B, C, D創建一個新對象時,你已經有了這些對象的向量成員。你也可以有一個虛擬函數convertToVec,你可以在子類中重寫,這取決於你想如何將數據轉換成矢量。

template<class T> 
class A { 
    std::vector<T> vec; 
    std::vector<T> GetVector() { return vec; } 
    virtual convertToVec() { .... } 
} 
class B : public A<bool> {} 
class C : public A<float> {} 
class D : public A<long long int> {} 

int main() { 
    B b; 
    b.GetVector(); 
    //A* b = new B(); 
    //b->convertToVec(); 
} 
1

雖然這是相當困難的遵循究竟你正在努力實現在這裏,將使用switch-case是不是一個好主意,而不是你最好充分利用多態性。例如:

class A { 
    public: 
     virtual void convertToVector(AuxVectorConverter& aux) = 0; 
}; 

class B { 
    public: 
     // Add here specific implementation 
     virtual void convertToVector(AuxVectorConverter& aux) { 
      aux.convertToVectorB(this); 
     } 
}; 

class C { 
    public: 
     // Add here specific implementation 
     virtual void convertToVector(AuxVectorConverter& aux) { 
      aux.doSomethingC(this); 
     } 
}; 

// Aux class 
class AuxVectorConverter { 
    public: 
     convertToVector(A* a) { 
      a->convertToVector(this); 
     } 

     convertToVectorB(B* b) { 
      // Do code specific for B 
     } 

     convertToVectorC(C* c) { 
      // Do code specific for B 
     } 
} 

int main() { 
    AuxVectorConverter* aux; 

    A* a = ...; // Initialize here either with instance of B or C 

    // Now, based on run time aux class will issue appropriate method. 
    aux.convertToVector(a); 
} 

您可能會發現更多的細節here


UPDATE(基於評論)

另一種做法可能是從TYPES定義地圖的一些抽象類,將與上面的模式對齊,例如:

​​

而且動作的定義與我上面顯示的層次非常相似,例如,

class AbstractAction { 
    public: 
     virtual void convertToVector(AuxVectorConverter& aux) = 0; 
}; 

class ActionB: public AbstractAction { 
    public: 
     virtual void convertToVector(AuxVectorConverter& aux) { 
      aux.covertToVectorB(this); 
     } 
}; 
+0

我從另一個庫中獲取所有這些類,除非創建派生類,否則我無法擴展它們。但這不是問題,問題是我的函數得到了對'A'類的實例的引用,我不知道應該將哪個類轉換爲它,除非我運行'getType'函數。所以我不得不求助於切換,在你的場景中,我必須用B或C實例初始化'A * a',但要知道哪一個我必須打開'getType'。至少這就是我迄今爲止對你的代碼的理解。那是對的嗎? – maga

+1

好的,如果你對班級沒有控制權,你仍然可以將它們包裝到你的層次結構中或裝飾它們。 –