2013-04-04 4 views
0

Как создать производный класс, который может изменить все переменные из экземпляра его базового класса? Я понимаю, что могу объявить переменные базового класса статическими, но когда я это делаю, я не могу их инициализировать с помощью функций, что делает код очень удобным и трудно редактировать.Производный класс из экземпляра класса?

Этот пример класса; почему c2 не редактирует x в классе C1. Если он ссылается на класс 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

+0

@fredrik Умм, почему? – Angew

+1

@fredrik: На самом деле это совершенно верно. Это нехорошо, и он включает в себя заголовки C, но он абсолютно корректен и будет компилироваться без каких-либо ошибок или предупреждений. – Zeta

ответ

1

theC1 и theC2 - полностью отдельные экземпляры. theC2 содержит подобъект типа c1, который инициализируется ссылкой ref, но он по-прежнему (и всегда будет) другим экземпляром c1, чем theC1. Субобъект базового класса является членом каждого экземпляра c2, и нет никакого способа сделать этот «общий» с любым другим экземпляром c2 или c1.

Вы можете сохранить ссылку внутри 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

Один из способов осуществить это в большем масштабе может быть c1 и c2 реализации и тот же интерфейс, и 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

+0

@ joelyboy94 Я расширил ответ. – Angew

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

+0

@ user2243911: Это может произойти, потому что я не вызвал правильный конструктор 'c1', см. Ответ Angew. Если вы вообще не хотите создавать 'c1', вы не должны наследовать его. – Zeta

Смежные вопросы