2010-06-23 2 views
0

У меня есть класс, унаследованный от абстрактного базового класса.Полиморфизм: доступ к переменной унаследованного класса

class CStateBase 
{ 
    friend class CApplication; 
    friend class CGraphics; 
    virtual int Update() =0; 
}; 

class CStateTitle: private CStateBase 
{ 
    friend class CApplication; 
    friend class CGraphics; 
    CApplication *f_App; 

    int m_iR; 

    int Update(); 

    CStateTitle(CApplication *App); 
    ~CStateTitle(); 
}; 

В методе другого класса, CStateTitle динамически распределяется в указатель CStateBase. Однако, если я использую этот указатель для попытки доступа к переменной int m_iR, компилятор ищет переменную в CStateBase и, следовательно, делает ошибку. Если бы я мог объявить виртуальный int m_iR в базовом классе, я бы подумал, что он будет работать нормально, но по какой-то причине он не позволяет мне объявлять членов виртуальных данных. Каков рекомендуемый способ обойти эту проблему? Спасибо за любую помощь.

+0

Скорее всего, вам нужен виртуальный деструктор в базовом классе, см., Например, Саттерс [Виртуальность] (http://www.gotw.ca/publications/mill18.htm). –

+1

Каким образом обычная не виртуальная переменная-член не решает вашу проблему? –

ответ

3

Лучший способ - отвлечь доступ m_iR к некоторой виртуальной функции.

Другим вариантом было бы перемещение m_iR от CStateTitle до CStateBase. Это имеет смысл только в том случае, если каждому классу нужен m_iR.

В крайнем случае будет делать динамическое приведение:

CStateBase *csb = ...; 

CStateTitle *cst = dynamic_cast<CStateTitle *>(csb); 
if (cst) 
{ 
    // have a valid CStateTitle 
} 
else 
{ 
    // csb is not pointing at a CStateTitle, do whatever is appropriate 
} 
+2

Ваша последняя идея совершенно верна, но ее следует избегать, если это возможно.Это красный флаг, который говорит, что вы не задумывались о своем полиморфизме. –

+0

@MarkRandom - Я согласен с тобой, поэтому я поместил этот вариант в последний раз. Я изменил свою формулировку на «последнее средство», чтобы подчеркнуть это. –

5

Вы должны наследовать публично от базового класса:

class CStateTitle: public CStateBase 

иначе CStateTitleнеCStateBase с точки составителя зрения, таким образом, вы не можете полиморфно доступ CStateTitle объектов через CStateBase указатель.

У вас нет виртуальных элементов данных, а только виртуальных методов на C++. Поэтому обходным путем может быть объявление метода (ов) виртуального доступа для вашего члена данных.

1

Поскольку вы пытаетесь получить доступ к члену производного класса непосредственно из указателя базового класса, вы, очевидно, не вызывая полиморфизм. Поэтому вы можете использовать dynamic_cast для доступа к этому члену.

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

0

Вы можете либо определить виртуальную функцию в базовом классе для выполнения требуемого доступа (getter и/или setter), либо вам нужно будет указать свой базовый указатель на производный * и продолжить оттуда.

1

У вас нет виртуальных переменных-членов.

Вы можете изменить, когда вы приводите:

CStateTitle *a = new CStateTitle(); 
a->m_iR = 1; 
CStateBase *b = a; 

или повторно отливать через некоторое время с помощью RTTI

CStateBase *a = new CStateTitle(); 
CStateTitle *b = dynamic_cast<CStateTitle*>(a); 
if(NULL != b) 
    b->m_iR = 1; 

или добавить виртуальный метод сеттер на базовый класс, если все CStateBase, где будут иметь некоторые int, которые необходимо установить.

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