2011-11-25 75 views
0

在我的程序中,我面臨着另一個困難(我將它們全部存儲起來,並在burts中提出許多問題:P)。我所做的是一個仿函數 - 那些仿函數都從DuplicateFn繼承而來 - 它有一個虛擬操作符(),每個孩子都要寫它的版本。新的,共享指針和虛擬函數

現在,其中一個孩子 - 稱爲合併 - 可能不會成功,在這種情況下,它應該嘗試回退方法。目前該類因此看起來像:

class MergeFn : public DuplicateFn { 
public: 
    MergeFn() : FallBack(new SkipFn()) 
    { 
    } 
    MergeFn(GMProject const* Out, GMProject const* In, DuplicateFn* f) 
     : DuplicateFn(Out, In), FallBack(f) 
    { 
    } 
    virtual void operator() (GMProject::pTree& tOut, const GMProject::pTree& tIn) const { 
     if (!GMProject::isMergeable(tOut.GetName())) { 
      (*FallBack)(tOut, tIn); //virtual table resolves this to the correct class 
     } else { 
     } 
    } 
private: 
    std::shared_ptr<DuplicateFn> FallBack; 
}; 

我認爲這個問題是清晰可見已經在這裏 - 在非默認構造函數,這種方法抓住給定參數的所有權。 - 這不是我想要的:它應該複製該參數並保留該參數的所有權。
現在我試着, FallBack(new DuplicateFn(f))但是,這也不起作用 - 因爲現在有一個編譯錯誤,它試圖用純虛擬方法實例化類中的對象。

那麼我該如何做到這一點? - 我必須爲每種類型指定一個特定的構造函數嗎? - 只是爲了正確地複製它?或者我必須通過RTTI?我希望有比一個更好的方法的2

編輯 要顯示mergeFn如何被初始化(和使用):

std::unique_ptr<detail::DuplicateFn> foo; 
foo.reset(new detail::MergeFn(this, &Other, DuplicateFns.at(HandleDuplicate))); 

DuplicateFns是地圖,這有助於實現功能轉換用戶輸入(串) -pointers。 - 或者因爲它是現在,指針從DuplicateFn(指針類型是DuplicateFn *)的子類型的對象

這隨後被用作回叫方法

ProjectTree.combine_if(tree, &SimilarTreeValue, foo.get()); 

其結合2種樹木成一個 - 當SimilarTreeValue返回true時,該條目被認爲是重複的。如果條目是一個葉子,第三個參數被稱爲 - 我們正在談論的仿函數:)。

回答

-1

您可以使用shared_ptr的構造函數,該構造函數採用自定義析構函數併爲其傳遞一個空函數。舉個例子。

void dontDelete(DuplicateFn *pFn) { 
    // Do nothing! 
    } 

class MergeFn : public DuplicateFn { 
public: 
    MergeFn() : FallBack(new SkipFn()) 
    { 
    } 

    MergeFn(GMProject const* Out, GMProject const* In, DuplicateFn* f) 
     : DuplicateFn(Out, In), FallBack(f, dontDelete) 
    { 
    } 

    virtual void operator() (GMProject::pTree& tOut, const GMProject::pTree& tIn) const { 
     if (!GMProject::isMergeable(tOut.GetName())) { 
      (*FallBack)(tOut, tIn); //virtual table resolves this to the correct class 
     } else { 
     } 
    } 

private: 
    std::shared_ptr<DuplicateFn> FallBack; 
}; 
+0

「_You可以使用的shared_ptr的構造函數需要一個自定義的析構函數,並傳遞一個空的功能it._」每當我讀到這,我覺得「試圖讓出了一個便宜的伎倆設計問題不會這樣做「。這是另一個例子。 「 – curiousguy

1

最簡單的方法(在我看來)是改變構造方法的簽名,要求已經是一個共享指針:

MergeFn(GMProject const * Out, 
     GMProject const * In, 
     std::shared_ptr<DuplicateFn> f) /* ... */ 

第二個選項是clone()功能賦予你的整個類層次結構:

struct Base 
{ 
    virtual Base * clone() const { return new Base(*this); } 
}; 

struct Der1 : Base 
{ 
    virtual Der1 * clone() const { return new Der1(*this); } 
}; 

然後你可以初始化FallBack(f->clone())

就我個人而言,我會與第一個版本,我也會檢查是否不可能用一個唯一的指針替換共享指針。

+0

」用一個唯一的指針替換共享指針。「爲什麼? – curiousguy

+0

@curiousguy:'unique_ptr'是一個非常輕量級(沒有動態分配,沒有虛擬調度)。如果你真的需要共享所有權,只能使用'shared_ptr'。 –

+0

「_如果你真的必須共享所有權,只能使用shared_ptr_」我在這裏看到至少兩個所有者:調用者和被調用者。類型爲'unique_ptr'的函數參數意味着所有權的轉移。如果來電者仍然想要所有權呢? – curiousguy

0

new DuplicateFn(f)

只會切片函子f

你需要一個克隆功能:

#include <typeinfo> 
#include <cassert> 

template <class T> 
// runtime checked clone function 
// T::do_clone() must be accessible to checked_clone 
T *checked_clone (const T* that) { 
    T *p = that->do_clone(); 
    assert (typeid (*p) == typeid (*that)); 
    return p; 
} 

// clone for an abstract class 
#define IMPLEMENT_CLONE_ABSTRACT(Class) \ 
    friend Class *checked_clone<Class> (const Class* that); \ 
\ 
public: \ 
    Class *clone_naked() const { \ 
     return checked_clone (this); \ 
    } \ 
    unique_ptr<Class> clone_unique() const { \ 
     return unique_ptr<Class> (checked_clone (this)); \ 
    } \  \ 
private: \ 
    virtual Class *do_clone() const = 0; \ 
/* end of IMPLEMENT_CLONE_ABSTRACT */ 

class Base { 
    IMPLEMENT_CLONE_ABSTRACT(Base) 
}; 

// clone for a concrete class 
#define IMPLEMENT_CLONE_CONCRETE(Class) \ 
    friend Class *checked_clone<Class> (const Class* that); \ 
\ 
public: \ 
    Class *clone_naked() const { \ 
     return checked_clone (this); \ 
    } \ 
    unique_ptr<Class> clone_unique() const { \ 
     return unique_ptr<Class> (checked_clone (this)); \ 
    } \  \ 
\ 
private: \ 
    virtual Class *do_clone() const { \ 
     return new Class (*this); \ 
    } \ 
/* end of IMPLEMENT_CLONE_CONCRETE */ 

class Derived : public Base { 
    IMPLEMENT_CLONE_CONCRETE(Derived) 
};