2013-01-22 2 views
3

У меня есть класс А с основными членами и функциями:что-то вроде виртуального члена (структура)

class A{ 
public: 
    typedef struct{ 
     int aa; 
     int bb; 
    } stEntry; 
    stEntry entry; 

    void function1(); 
    void function2(); 
}; 

чем класс B, который должен расширить класс А, включая структуры stEntry ...

class B : public A{ 
public: 
    typedef struct :stEntry 
    { 
     int cc; 
    } stEntry; 
    stEntry entry; 

    void function3(); 
}; 

, а затем :

int main() { 
    A a; 
    B b; 
    a.entry.aa = 1;  
    b.entry.aa = 2; 
    b.entry.cc = 3; 

    cout << "class A:"<<sizeof(a)<< endl; 
    cout << "class B:"<<sizeof(b)<< endl; 

    return 0; 
} 

Я получаю

class A:8 
class B:20 

Таким образом, класс B содержит 2 экземпляра - 8 байтов (член класса) + 12 байтов (член класса B).

Есть ли способ расширения структуры stEntry для класса B? (без 2 экземпляров)

ответ

2

Сорт с виртуальным наследованием:

struct stEntryBase { 
    int aa; 
    int bb; 
}; 

struct A : virtual stEntryBase { 
    typedef stEntryBase stEntry; 

    void function1(); 
    void function2(); 
}; 

struct stEntryDerived : virtual stEntryBase { 
    int cc; 
}; 

struct B : A, stEntryDerived { 
    typedef stEntryDerived stEntry; 

    void function3(); 
}; 

Если вы хотите пойти еще один уровень наследования затем B бы производный практически из stEntryDerived.

Теперь вы должны обращаться к полям как a.aa, b.cc, нет ни одного участника entry. Кроме того, типы stEntry больше не являются POD (поэтому bb и cc больше не могут быть смежными в памяти). Наконец, увеличение размера из-за виртуального наследования может фактически быть больше двух int с.

Что вы можете сделать, это получить stEntryDerived* или stEntryDerived& от экземпляра B. Затем этот указатель/ссылку можно использовать для доступа к aacc в качестве членов stEntryDerived, без необходимости знать пользователя о B. Таким образом, вы достигли разделения интерфейса, по какой-то причине.

+0

Thats great idea! Тем не менее, я думаю, что строки «typedef stEntryBase stEntry»; и "typedef stEntryDerived stEntry;" являются избыточными. – Meloun

+0

@Meloun: конечно, я оставил их на всякий случай, если есть код вызова, который использует тип 'B :: stEntry' для чего-либо. –

4

Нет, потому что вы создаете два экземпляра самостоятельно. Базовый класс имеет экземпляр, а производный класс имеет экземпляр (класса, расширяющего внутренний класс базового класса).

Вы не можете изменить структуру базового класса вне его - после того, как вы определили его, он останется таким.

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