2011-07-17 69 views
2

我有一個問題,我不知道如何處理它。首先,我是初學者。我有一個類和兩個引用變量聲明的兩個構造函數,但我不能在一個構造函數中使用兩個引用。如果cons1()被調用,我需要ref1被使用,如果cons2被調用,我需要ref2被使用。問題在於我應該如何引用ref1,何時調用cons2,以及類似於調用cons1時ref2應該引用的內容。我不確定如何初始化這些引用。它不能爲NULL。我不確定指出一些無效的實現是否是一個好主意。應該是?這甚至是一個選擇嗎?在C++中如何處理這樣的問題?可選的參考實現

// A.cpp 
Class A 
A(Object1& a) : ref1(a) {} - here how should ref2 be handled? 
A(Object2& b) : ref2(b) {}- here what should ref1 reference? 

// A.h 
Object1& ref1 
Object2& ref2 

我需要在這裏使用引用。我明白我們可以使用指針而不是引用,但問題是使用引用的特定問題。

+0

你可以改進問題標題嗎?我們知道這是一個問題,因爲您發佈了它,並且我們知道它是C++,因爲它是如此標記的。 –

+2

*「我需要在這裏使用參考」* - 爲什麼對自己施加任意限制?如果確實如此,那麼我會投票結束,因爲太局部化了。如果這是一個真正的編程問題,我們使用正確的工具進行工作,我們不會對自己施加任意限制。 –

+1

雖然問題確實出現在我的個人工作中,但它不僅僅是一個本地化的問題。一般來說,問題是我們如何處理C++中的這種情況。如果使用指針代替refs是唯一的解決方案,那麼我們可以關閉它,說出那個soln。 – leonidus

回答

7

由於REF1和REF2是可選的(不是必須的),那麼最好是使用指針,而不是引用:

class A 
{ 
    public: 
    A(Object1& a) : ref1(&a), ref2(NULL) {} 
    A(Object2& b) : ref1(NULL),ref2(&b) {} 

Object1 *ref1; 
Object2 *ref2; 
}; 

但後來你必須檢查REF1和REF2是NULL。

+0

這個答案是正確的。不過,這似乎是一個糟糕的方法來接收代碼。 –

+0

@Tomalak爲什麼?我猜你可以使用boost :: optional –

+2

因爲該對象被賦予了基於不超過構造函數參數類型的非常不同的語義。你必須非常小心,'Object1'和'Object2'之間沒有隱含的轉換,否則你會得到意想不到的行爲,並且在'A'中的每個函數中,你將不得不檢查使用哪個和重複代碼取決於它是哪個地方。根據更廣泛的用例,接口式基類和兩個派生類變體可能會更有意義。 –

0

如果你需要有NULL值,你應該從引用切換到指針。一些編譯器支持NULL引用,但這是糟糕的風格,不便攜,因此應該避免。

+0

所有編譯器都支持NULL引用。問題是 - 取消引用NULL引用對象是一個UB。 –

+1

什麼編譯器?根據定義,一個引用(在C++中)**不能**爲NULL –

+0

我相信NULL在stdlib.h中定義.... – Prime

2

警告:以下是愚蠢和做作。爲什麼?因爲使用引用的要求也是如此。

class base { 
    virtual 
    ~base(); 

    virtual 
    void 
    stuff_happens() = 0; 
}; 
base::~base() = default; 

class case1: public base { 
public: 
    explicit 
    case1(Object1& o) 
     : ref(o) 
    {} 

    void 
    stuff_happens() 
    { 
     // we use ref here 
    } 

private: 
    Object1& ref; 
}; 

class case2: public base { 
public: 
    explicit 
    case2(Object2& o) 
     : ref(o) 
    {} 

    void 
    stuff_happens() 
    { 
     // we use ref here 
    } 

private: 
    Object2& ref; 
}; 

std::unique_ptr<base> 
make_base(Object1& o) 
{ return std::unique_ptr<base>(new case1(o)); } 

std::unique_ptr<base> 
make_base(Object2& o) 
{ return std::unique_ptr<base>(new case2(o)); } 

// ... 
{ 
    auto p = condition ? make_base(ref1) : make_base(ref2); 
    p->stuff_happens(); 
} 
1

正確答案已經給出:切換到指針。這種情況下的參考文獻提供了零利益,正如你所看到的那樣,有一個巨大的缺點。你的設計是可疑的開始;讓我們不要因爲引入額外的不良要求而使事情複雜化。

但是,如果你堅持使用引用,唯一可能的解決方案是引入某種標記值。

struct A { 
    A(Object1& o) : obj1(o), obj2(null2) { } 
    A(Object2& o) : obj1(null1), obj2(o) { } 

    void function() { 
     if(&obj1 == &null1) 
      //Object2 constructor 
     else 
      //Object1 constructor 
    } 

    private: 
    Object1& obj1; 
    Object2& obj2; 

    static Object1 null1; 
    static Object2 null2; 
}; 

//implementation file 
Object1 A::null1; 
Object2 A::null2; 

此方法取決於Object1Object2兩者都具有默認構造函數,或以其它方式具有用於哨兵一個合理的默認值。 null1null2都將在應用程序的整個生命週期中存在,所以如果他們獲得任何資源,您將基本上有泄漏。

對於哨兵的無效使用,您也必須小心謹慎,因爲[一般情況下]此類訪問非常安全。有一個強有力的論據可以說,錯誤導致可能會崩潰的未定義行爲比導致定義良好的行爲可能會產生意想不到的結果更好。