2013-01-17 27 views
0

我的問題涉及公共和私有繼承的組合作爲分離C++類中的接口和實現的工具。在此模式中,接口基類聲明瞭常用功能(class Base0)。常見的實現是在一個從接口基礎(class Impl0 : virtual public Base0)虛擬派生的類中執行的。這個類包含任何常見的數據成員。擴展類分兩步寫入。首先,擴展接口由接口基地的虛擬繼承來定義(class Base1 : virtual public Base0)。其次,通過公開從Base1(用於接口)和私人從Impl0(用於實現)推導出擴展實現:class Impl1 : public virtual Base1, private Impl0。我的問題如下:實現層次結構中的冗餘私有成員數據複製

(1)如果擴展類中的函數定義的函數需要Impl0中的公用數據,那麼我必須在「Impl1」中複製那些數據嗎?

(2)有什麼辦法可以避免這種複製?作爲一個最基本的例子,考慮實現四個基本算術函數的類層次結構:add(),substr(),mult()和div()。基本版本MathOps包含add()和subtr()函數。擴展版本MathOps_Extn包含mult()和div()。上述技術提供了以下類層次結構。

#include<iostream> 

using std::cout; 
using std::endl; 

class MathOps { 
public: 
    virtual int add(int x) = 0; 
    virtual int subtr(int x) = 0; 
}; 

class MathOps_Impl : public virtual MathOps { 
private: 
    int m_y; 
public: 
    MathOps_Impl(int y) : m_y(y) { 
    cout << "MathOps_Impl initialized with value: " << m_y << endl; 
    } 

    virtual int add(int x) { return x + m_y;} 
    virtual int subtr (int x) { return m_y - x;} 
}; 

class MathOps_Extn : public virtual MathOps { 
    // Extends MathOps by adding mult() and div()                                 
public: 
    virtual int mult(int x) = 0; 
    virtual int div(int x) = 0; 
}; 

class MathOps_Extn_Impl : public virtual MathOps_Extn, private MathOps_Impl { 
private: 
    int m_y; // Have to replicate member data m_y here.                               
public: 
    MathOps_Extn_Impl(int y) : MathOps_Impl(y), m_y(y) { 
    cout << "MathOps_Extn_Impl initialized with value: " << m_y << endl; 
    } 

    virtual int mult(int x) { 
    return x * m_y; 
    } 
    virtual int div(int x) { 
    int quotient = x == 0? 0 : m_y/x; 
    return quotient; 
    } 
}; 

int main() {                                   
    MathOps_Extn* B = new MathOps_Extn_Impl(10); 
    cout << "add 20: " << B->add(20) << endl; 
    cout << "subtr 20: " << B->subtr(20) << endl; 
    cout << "mult 2: " << B->mult(2) << endl; 
    cout << "div 5: " << B->div(5) << endl; 

m_yMathOps_Extn_Impl複製。有什麼辦法可以避免這種複製?

+3

誰願意適應算術運算成一個層次化的設計? –

+0

再走一步,並擁有一個MathOps_Extn_base?或者把m_y放在MathOps中 – dchhetri

+0

爲什麼不使用'protected'?但是如果你想用'private'修飾符繼承,那麼你必須重複它。把'm_y'放在接口中而不把'private'改成'protected'不會有太大的改變。 編輯:關於第一個問題,看看如何在C++中查找名稱。如果你把'm_y'作爲'Impl0'的保護對象,那麼你應該可以在'Impl1'中使用它。 –

回答

0

通過通用實現類中的受保護成員函數,您可以在不破壞封裝的情況下訪問公用數據。

無償例子如下:)

#include <cstdio> 

class Math 
{ 
public: 
    virtual ~Math() {} 
    virtual int add(int b) const = 0; 
}; 

class MoreMath : public virtual Math 
{ 
public: 
    virtual ~MoreMath() {} 
    virtual int subtract(int b) const = 0; 
}; 

class MathImpl : public virtual Math 
{ 
private: 
    int m_a; 

public: 
    MathImpl(int a) : m_a(a) {} 
    virtual ~MathImpl() {} 
    int add(int b) const { return m_a + b; } 

protected: 
    int value() const { return m_a; } 
}; 

class MoreMathImpl : public virtual MoreMath, private MathImpl 
{ 
public: 
    MoreMathImpl(int a) : MathImpl(a) {} 
    int subtract(int b) const { return value() - b; } 
}; 

int main() 
{ 
    MoreMath* one = new MoreMathImpl(1); 
    printf("1 + 2 = %d\n", one->add(2)); 
    printf("1 - 2 = %d\n", one->subtract(2)); 
    delete one; 

    return 0; 
} 
+0

謝謝。我已經接受了你的回答,因爲它避免了受保護的成員數據。 – RDK

1

請注意在MathOps_Extn_Impl中複製m_y。有沒有辦法來 避免這種複製?

是的。給MathOps_Impl::m_yprotected訪問而不是private

您明確地問爲什麼派生類不能訪問私人數據。這是設計。

+0

我意識到'private'基類成員的不可訪問性。然而,請看我對PiotrJaszkowski的評論,因爲我對使用'protected'感到不安。可能是'被保護的'是要走的路,我只是覺得它打破了封裝。 – RDK

+0

@RDK我同意你的評論,它可以打破封裝。 K-ballo也提出了封裝設計異常的有效評論。 –