2016-11-14 70 views
-1

我遇到以下問題:使用庫(它是hdf5庫,但沒關係)。
我想做類似以下的事情,但我認爲我不能,因爲基類是抽象的。換句話說,我不能遲到綁定,因爲我不能實例化一個抽象類的對象。如何避免無法實例化抽象類的問題

我有一個抽象類和2個派生類。 main()的代碼不正確,因爲我不能執行Base theObject;

//An abstract class 
class Base 
{ 
protected: 
    Base() {} 
public: 
    void doSomething() = 0; 
}; 

class DerivedA : public Base 
{ 
public: 
    DerivedA() : Base() {} 
    void doSomething() {cout << "I am a DerivedA" << endl;} 
}; 

class DerivedB : public Base 
{ 
public: 
    DerivedB() : Base() {} 
    void doSomething() {cout << "I am a DerivedB" << endl;} 
}; 


int main() 
{ 
    // A special function returns the type of object that it is placed at "thePath". 
    int theType = someSpecialFunction(thePath); 
    Base theObject; //This is not possible. 
    switch (theType) 
    { 
     case 1: //A derivedA object 
     { 
      theObject = openObjectOfTypeA(thePath); //Special function of the library.    
      break; 
     } 
     case 2: //A derivedB object 
     { 
      theObject = openObjectOfTypeB(thePath); //Special function of the library 
      break; 
     } 
    } 

    theObject.doSomething(); 
    //whatever 
} 

我可以做類似以下的事情。但是,在真實場景中,我會以很多重複的代碼結束。

int main() 
{ 
    // A special function returns the type of object that it is placed at "thePath" 
    int theType = someSpecialFunction(thePath); 
    switch (theType) 
    { 
     case 1: //A derivedA object 
     { 
      DerivedA theObject = openObjectOfTypeA(thePath); 
      theObject.doSomething(); 
      break; 
     } 
     case 2: //A derivedB object 
     { 
      DerivedB theObject = openObjectOfTypeB(thePath); 
      theObject.doSomething(); 
      break; 
     } 
    } 
    //whatever 
} 

有沒有什麼方法可以避免我的「解決方案」? 預先感謝您。

+3

你不能有實例,但你可以有指針,你可以使用'Base * theObject'。無論如何,由於對象切片,Base theObject = DerivedA();被打斷(與Base的抽象無關) – user463035818

+0

語言提供了多態性,因此您不必在類型和向下轉換時進行調度。 –

+0

@ tobi303關於對象切片問題。如果我僅使用Base * theObject指針調用doSomething(),那麼沒有問題嗎? –

回答

4

你可以有

Base* theObject;

,並使用指針調用成員函數。您將必須更改返回類型openObjectOfTypeA/B以返回指向Base類的指針。在基類

theObject->doSomething();

+0

我無法更改函數openObjecOfTypeA/B(它們是庫的一部分)。因此,我將不得不這樣做:'DerivedA tmpObj = openObjectOfTypeA(thePath); theObject =&tmpObj;'在開關'theObject-> doSomething'之後。對?非常感謝。這種方法有什麼危險嗎? –

+0

@pablo_worker'theObject'指針應該指向一個有效的地址,確保你不解引用那些不包含有效地址的東西。 'tmpObj'可能會超出範圍,您將不得不照顧。另外它很好地分配'Base * theObject = nullptr;'所以你可以在解引用它之前總是檢查'nullptr'。 – P0W

+0

好的。非常感謝。 –

1

只有虛擬方法可以是抽象的,所以你的第一類應該protyped doSomething的,因爲這:

虛擬無效的doSomething()= 0;

你可以通過使用指針來使用「type」參數。指向基類(例如Base)的指針可指向任何派生類(例如DerivedA或DerivedB)。然後,當你想調用doSomething()時,它會調用子類的doSomething。

1

您可以將其封裝在工廠功能中。

std::unique<Base> getObject(... thePath) 
{ 
    const int theType = someSpecialFunction(thePath); 
    switch (theType) 
    { 
     case 1: //A derivedA object 
      return std::make_unique<DerivedA>(openObjectOfTypeA(thePath)); 
     case 2: //A derivedB object 
      return std::make_unique<DerivedB>(openObjectOfTypeB(thePath)); 
    } 
    return nullptr; 
} 


//...  
std::unique<Base> basePtr = getObject(path); 
basePtr->doSomething(); 
//... 

如果沒有C++ 14提供你可以更換unique_ptr與升壓shared_ptr或原始指針。