2013-04-04 125 views
0

我該如何製作一個派生類,它可以改變其基類實例的所有變量?我知道我可以聲明基類變量是靜態的,但是當我這樣做時,我無法使用函數初始化它們,這使得代碼非常消息且難以編輯。來自類實例的派生類?

這是一個示例類;爲什麼c2不能在theC1類中編輯x。如果它引用的是不是C1的c1類,那麼引用的是什麼?

#include <stdio.h> 

class c1 
{ 
public: 
    c1(int d) 
    { 
     x = d; 
    } 
    int x; 
}; 

class c2 : public c1 
{ 
public: 
    c2(c1& ref) 
     : 
    c1(ref) 
    {}; 
    void setx() 
    { 
     x = 5; 
    } 
}; 

int main() 
{ 
    c1 theC1(4); 
    c2 theC2(theC1); 
    theC2.setx(); 

    printf("%d\n",theC1.x); 
    printf("%d\n",theC2.x); 

    return 0; 
} 
+1

這甚至不應該編譯......或者至少要給出大量的警告。 – fredrik 2013-04-04 08:45:12

+0

@fredrik嗯,爲什麼? – Angew 2013-04-04 08:51:12

+1

@fredrik:其實它是完全有效的。這不是很好,它包含C頭文件,但它是完全有效的,並且將在沒有任何錯誤或警告的情況下進行編譯。 – Zeta 2013-04-04 08:51:25

回答

1

theC1theC2是完全獨立的實例。 theC2包含c1類型的子對象,該對象由參考號ref初始化,但它仍然(並且總是)將是c1的另一個實例,而不是theC1。基類子對象是每個c2實例的成員,並且無法與其他任何c2c1的實例「共享」。

如果那是您之後的語義,您可以將引用存儲在c2之內並訪問該引用,而不是從c1派生。然後,該代碼是這樣的:

class c1 
{ 
public: 
    c1(int d) 
    { 
     x = d; 
    } 
    int x; 
}; 

class c2 
{ 
    c1 &myC1; 
public: 
    c2(c1& ref) 
     : 
    myC1(ref) 
    , x(myC1.x) 
    {} 
    void setx() 
    { 
     myC1.x = 5; 
    } 
    int &x; 
}; 

當然,這將是更好的封裝x,而不是把它公開,並不得不訴諸引用的技巧,比如那些在上面的代碼。

UPDATE

一種方式來實現這在更大的範圍可能是c1c2實現相同的接口,並c2實例共享的c1「數據實例」:

#include <memory> 


struct c1_iface 
{ 
    virtual int getX() const = 0; 
    virtual void setX(int newX) = 0; 
}; 


class c1 : public c1_iface 
{ 
    int x; 

public: 
    virtual int getX() const { return x; } 
    virtual void setX(int newX) { x = newX; } 
}; 


class c2 : public c1_iface 
{ 
    std::shared_ptr<c1> data_; 

public: 
    explicit c2(std::shared_ptr<c1> data) : data_(data) {} 

    virtual int getX() const { return data_->getX(); } 
    virtual void setX(int newX) { data_->setX(newX); } 
}; 

如果您無權訪問C++ 11,您可以改爲使用boost::shared_ptr(或僅使用手動共享,並非真正推薦)。

作爲一個稍微髒兮兮的替代方案,您可以將共享指針(或其等價物)移動到c1_iface中,並使函數非抽象,對其進行解引用。

+0

感謝您的幫助。這就是我想要做的事情,除了一點清潔劑。如果在基類實例中沒有派生類共享變量的方法,那麼讓大量類訪問類c1實例的變量的最佳方法是什麼? – joelyboy94 2013-04-04 11:20:30

+0

@ joelyboy94我已經擴大了答案。 – Angew 2013-04-04 11:42:12

2

您使用的參考調用c1拷貝構造函數,而不是保存到c1對象的引用。你想是這樣的:

class c2 : public c1 
{ 
public: 
    c2(c1& ref) 
     : c1_ptr(&ref) {} 

    void setx() 
    { 
     c1_ptr->x = 5; 
     this->x = 5; 
    } 
private: 
    c1 * c1_ptr; 
}; 

然而,這需要一個默認構造函數c1。如果你不希望任何建設可言,你可能需要使用一個代理類:

class c1_proxy 
{ 
public: 
    c1_proxy(c1& ref) 
     : x(ref.x), c1_ptr(&ref) {} 

    void setx() 
    { 
     c1_ptr->x = 5;   
    } 
    int & x; 
private: 
    c1 * c1_ptr; 
}; 

不過,我認爲這是一個反模式。請注意,您必須手動更新所有值。

+0

嗨,謝謝你的回答。我試過,但它說c1沒有默認的構造函數。問題是我不想構造一個c1,我只想引用或指向一個c1的實例。 – joelyboy94 2013-04-04 08:51:51

+0

@ user2243911:這可能發生是因爲我沒有調用'c1'的正確構造函數,請參閱Angew的答案。如果你不想構建'c1',你不應該繼承它。 – Zeta 2013-04-04 08:56:11