2013-02-26 2 views
0

я мог бы иметь неправильное представление о точно, что полиморфизм против наследования, но в основном то, что я пытаюсь сделать, это ClassB проистекают из CLASSA, и создать ClassB который переопределяет чистую виртуальную функцию-член CLASSA, как так:полиморфизм/вопрос наследования с функцией члена виртуального класса


CLASSA:

///////////////// 
// CodeBlock.h // 
///////////////// 

typedef enum { 
    CCBT_UNDEFINED, 
    CCBT_FUNCTION, 
    //... 
} CODE_BLOCK_TYPE; 

class CCodeBlock { 
public: 
    CCodeBlock::CCodeBlock(); 
    CCodeBlock::CCodeBlock(CString& source, DWORD startPos); 
    CCodeBlock::~CCodeBlock(); 
    virtual CODE_BLOCK_TYPE CCodeBlock::GetType() = 0 

    CString m_code; 
    DWORD m_startPos; 
    DWORD m_length; 
    int m_numLines; 
} 

    /////////////////// 
// CodeBlock.cpp // 
/////////////////// 

//... 
CCodeBlock::CCodeBlock(CString& source, DWORD startPos) : m_code(source), m_startPos(startPos) { 
    m_length = m_code.GetLength(); 
} 

CODE_BLOCK_TYPE CCodeBlock::GetType() { 
    return CCBT_UNDEFINED; 
} 


ClassB:

///////////////////// 
// FunctionBlock.h // 
///////////////////// 

#include "CodeBlock.h" 

class CFunctionBlock : public CCodeBlock { 
public: 
    CFunctionBlock::CFunctionBlock(); 
    CFunctionBlock::CFunctionBlock(CString& source, DWORD startPos); 
    CFunctionBlock::~CFunctionBlock(); 
    CODE_BLOCK_TYPE CFunctionBlock::GetType(); 
} 

    /////////////////////// 
// FunctionBlock.cpp // 
/////////////////////// 

//... 
CFunctionBlock::CFunctionBlock(CString& source, DWORD startPos) 
{ 
    m_code = source; 
    m_startPos = startPos; 
} 

CFunctionBlock::~CFunctionBlock() 
{ 
    CCodeBlock::~CCodeBlock(); 
} 

CODE_BLOCK_TYPE CFunctionBlock::GetType() 
{ 
    ////////////////////////////// 
    // >> NEVER GETS CALLED! << // 
    ////////////////////////////// 
    return CCBT_FUNCTION; 
} 


главная:

CCodeBlock *block = new CFunctionBlock(L"function hello(){ print('hello') }", iPos) 
CODE_BLOCK_TYPE type = block->GetType(); // ALWAYS RETURNS CCBT_UNDEFINED! 


Как вы можете видеть, GetType() всегда возвращает CCBT_UNDEFINED. Имейте в виду, что CCodeBlock должен быть «общей» версией CFunctionBlock (а также несколькими другими аналогичными классами, некоторые из которых содержат переменную-член класса CCodeBlock «m_parent») и должны наследовать любые переменные-члены CCodeBlock &, а также переопределить определенный список функций, содержащихся в CCodeBlock.

Как это можно достичь? Придется ли мне прибегать к использованию шаблонов (если это возможно)?

+3

Кстати, вам не нужно 'CCodeBlock ::', когда вы объявляете функции-члены внутри класса 'CCodeBlock' – billz

+1

Кроме того, типы не совпадают. 'CCodeBlock CFunctionBlock :: GetType()' vs 'CODE_BLOCK_TYPE CCodeBlock :: GetType()'. Скомпилирует ли этот код? – Matthew

+0

@billz - это опечатка с копией/вставкой, за исключением CFunctionBlock :: GetType() - которая, похоже, все время была проблемой. После удаления «CFunctionBlock ::», block-> GetType() теперь возвращает CCBT_FUNCTION. Так спасибо за это! Если вы опубликуете это как ответ, я отдам ему за него. – RectangleEquals

ответ

1

Довести комментарий как ответ:

вам не нужно CCodeBlock:: при объявлении функций-членов внутри класса CCodeBlock

+0

Фактическая проблема была в CFunctionBlock, а не в CCodeBlock. Но это достаточно близко. Еще раз спасибо! – RectangleEquals

1

Есть несколько вещей неправильно с вашим кодом. Объявления участников не должны имеют название класса в качестве квалификации (то есть CCodeBlock:: следует удалить из объявлений). Оставляя это, делает код плохо сформированным.

Кроме того, деструктор производного типа будет неявным образом вызвать деструктор базового класса, и вы не должны этого делать. Если вы вызовете его вручную, базовый подобъект будет уничтожен дважды, что, вероятно, приведет к неопределенному поведению (если базовый деструктор не является тривиальным).

Теперь конкретный вопрос с вашим кодом в main был, вероятно, больше, как это:

CCodeBlock *block 
    = new CFunctionBlock(L"function hello(){ print('hello') }", iPos) 
CODE_BLOCK_TYPE type = block->CCodeBlock::GetType(); 
//       ^^^^^^^^^^^^ 

В C++, квалифицируя вызов функции отключает динамическую диспетчеризацию. Выражение block->GetType() будет отправлено на конечный переопределитель динамического типа объекта, на который указывает указатель block. Но если вы добавите квалификацию: block->CCodeBlock::GetType(), вы просите компилятор вызывать overrider на уровне CCodeBlock.

+0

Это имеет смысл. Я удалил все вызовы базового деструктора из моего источника, спасибо! И что касается 'block-> CCodeBlock :: GetType()', цель заключалась в том, чтобы вместо 'block-> GetType()' call_ block-> CFunctionBlock :: GetType() ', что я мог сделать как только я удалил _'CFunctionBlock :: '_ из 'CODE_BLOCK_TYPE CFunctionBlock :: GetType();' в _FunctionBlock.h_ – RectangleEquals

+0

@RectangleEquals: Вы понимаете, что я сказал в ответе относительно 'block-> CCodeBlock :: GetType()', правильно? Я не уверен, достаточно ли это ясно: если вы квалифицируете вызов функции с именем класса, вы отключите динамическую отправку и принудительно вызовите вызов на этом уровне. –

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