2011-02-16 133 views
9

鑑於這種人爲的例子:C++成員函數鏈接返回類型和派生類

struct point_2d { 
    point_2d& x(int n) { 
    x_ = n; 
    return *this; 
    } 

    point_2d& y(int n) { 
    y_ = n; 
    return *this; 
    } 

    int x_, y_; 
}; 

struct point_3d : point_2d { 
    point_3d& z(int n) { 
    z_ = n; 
    return *this; 
    } 

    int z_; 
}; 

int main() { 
    point_3d p; 
    p.x(0).y(0).z(0); // error: "point_2d" has no member named "z" 
    return 0; 
} 

的想法是使用「成員函數鏈」,以便能夠調用多個成員函數在一排。 (有很多這樣的例子,上面是我能想到的最短的一個,用於提出這個問題,我的實際問題是類似的,下面會有描述。)

問題是如果派生類增加它自己的鏈接成員函數,但是你首先調用一個基類的成員函數,你會得到一個基類引用,當然這對於調用派生類的成員函數來說是無效的。

有沒有什麼聰明的方法來解決這個問題,仍然保持成員函數鏈接的能力?


企業的實際問題

實際問題是,我的基類是個例外,我的派生類是從基本異常派生的類。對於這些類也,我想使用成員函數鏈接:

class base_exception : public std::exception { 
    // ... 
    base_exception& set_something(int some_param) { 
    // ... 
    return *this; 
    } 
}; 

class derived_exception : public base_exception { 
    // ... 
}; 

int main() { 
    try { 
    // ... 
    if (disaster) 
     throw derived_exception(required_arg1, required_arg2) 
      .set_something(optional_param); 
    } 
    catch (derived_exception const &e) { 
    // terminate called after throwing an instance of 'base_exception' 
    } 
} 

的問題是,set_something()回報base_exceptioncatch期望一個derived_exception。當然,一個人類可以告訴,異常的實際類型是derived_exception,但編譯器顯然不能說。

這就是我真正想要解決的問題,即如何讓基本異常類能夠在異常對象上設置可選參數,然後返回派生類型的實例。上面給出的point_2d例子是(我相信)人們理解的同一個問題的一個更小和更簡單的版本,並且小問題的解決方案也將解決我的實際問題。

請注意,我沒有考慮做base_exception模板,並在派生類傳似:

template<class Derived> 
class base_exception { 
    // ... 
    Derived& set_something(int some_param) { 
    // ... 
    return *this; 
    } 
}; 

我相信事實並解決問題,但它不是一個完美的解決方案,因爲如果其他類more_derived_exception導出從derived_exception,那麼我們又回到了同樣的問題。

+1

的`base_exception <類派生>你有你的問題的最後是被稱爲奇異遞歸模板模式(CRTP)`想法。我認爲它不會爲您的情況提供解決方案,因爲您的異常層次結構中無法使用單個根基類。 – 2011-02-16 17:43:14

+0

@艾米爾:是的,我說這不是一個完美的解決方案,爲什麼。 – 2011-02-16 17:54:44

+0

我只是指出,爲了其他讀者的利益,你顯示的模式有一個特定的名稱。我還給出了另一個原因,爲什麼(不同於你的)解決方案不起作用。我不打算批評你。 :-) – 2011-02-16 19:46:17

回答

0

你爲什麼不走了,最簡單的方法(也許不是最優雅):

if (disaster) 
{ 
    derived_exception e = derived_exception(required_arg1, required_arg2); 
    e.set_something(optional_param); 
    throw e; 
} 

那不是解決你的問題還是我錯過了什麼?

7

你在找什麼是Named Parameter Idiom,我從this StackOverflow answer複製。您不是返回對實際對象的引用,而是返回對特殊參數對象的引用,並且依賴於異常對象的構造函數在所有參數填充後執行隱式轉換。實際上,它非常聰明。

1

您好 我剛剛有了一個類似的問題,我在這裏的解決方案:

template<class DerivedOptions> 
class SomeOptions 
{ 
    private: 
    DerivedOptions* derived; 
    int param1_; 
    public: 
    SomeOptions() 
    { 
     derived = reinterpret_cast<DerivedOptions*>(this); 
    } 

    DerivedOptions & set_some_options(int param1) 
    { 
     param1_ = param1; 
     return *derived; 
    } 
}; 

struct MoreOptions: public SomeOptions<MoreOptions> 
{ 
    private: 
    int more_; 
    public: 
    MoreOptions & set_more_options(int more) 
    { 
     more_ = more; 
     return *this; 
    } 
}; 

Defininately包含了一些我知道我在做什麼,但是富而另一方面(至少在我的應用程序)的基礎沒有繼承就不能使用類。

最好的問候, 註冊查詢

相關問題