2015-12-30 5 views
1

Я все еще изучаю основы C++, но сейчас я работаю над проектом с использованием производных классов и виртуальных методов. Так что ситуация: У меня есть CLASSAПередача указателя на один производный класс другому

class ClassA 
{ 
public: 
    virtual void action(); 
}; 

И есть две производные классы B и C:

#include "ClassA.h" 

class ClassB: public ClassA 
{ 
public: 
    virtual void action(); 
    int valueB; 
}; 

-

#include "ClassA.h" 

class ClassC: public ClassA 
{ 
public: 
    virtual void action(); 
    int valueC; 
}; 

Я хочу передать указатель на объект ClassB как параметр action() в ClassC, поэтому я могу сделать что-то вроде этого:

void ClassC::action(ClassB * ptr) 
{ 
cout << "The value is: " << ptr->valueB; 
} 

Однако я не могу найти рабочий способ для этого. Все указатели объектов хранятся в

vector<ClassA *> objects 

где

objects[0]=new ClassC(); 
objects[1]=new ClassB(); 

если я пытаюсь что-то вроде

objects[0]->action(object[1]) 

тогда мне нужен мой виртуальный метод в ClassA иметь параметр ClassB * , А затем для программы, чтобы распознать тип, который я попробовал, либо включая весь класс Class.h (плохая идея, он создает «цикл» включений или что-то еще) или с использованием класса декларации Forward Class Class Class; (Я получаю сообщение об ошибке недопустимого использования неполного типа). И поэтому я сейчас застрял. Я надеюсь, что все ясно, но я могу, конечно, предоставить больше данных, если это необходимо.

+0

Право. потому что было бы небезопасно слепо опускать «A *» на «B *» –

+0

, что бы избавиться от valueB и valueC и просто иметь значение int; в ClassA? – tetorea

+0

Вы бы использовали декларацию класса ClassB в заголовке другого класса и include в cpp-файле. Вместе с Sentinel, как описано ниже, это позволит избежать цикла ... –

ответ

2

Когда вам нужно перенаправить объявление, это потому, что вы не можете включить все определение класса. В этой ситуации, если вы пересылаете объявление ClassB, компилятор не знает об атрибуте участника valueB, поэтому вы получаете ошибку неполного типа. Для того, чтобы решить эту проблему, вы должны учитывать код что-то вроде:

//ClassA.h 
class ClassB; 

class ClassA 
{ 
    virtual void action(ClassB* ptr); 
} 

//ClassA.cpp 
#include "ClassB.h" 
void ClassA::action(ClassB* ptr) { ... } 

Таким образом, вы в основном с помощью заголовка, чтобы объявить виртуальный метод и вперед объявить ClassB, но определить его в ClassA.cpp, так что в исходном файле вы может включать ClassB.h без проблем и без риска круговых зависимостей.

+0

Я просто протестировал это решение, и он работает очень хорошо. Единственное отличие состоит в том, что я включил ClassB.h в ClassC.cpp вместо ClassA.cpp. Ваше решение привело к той же ошибке (неполный тип). Я не уверен, почему, но может быть, потому что ClassC.h включает ClassA.h (где есть объявление вперед), но не знает о ClassA.cpp (где фактическое определение есть)? – nabacc001

0

Вы можете определить action (во всех классах) как:

virtual void action(ClassA * ptr); // or ClassB * 

Затем вы можете передать любой экземпляр ClassA или производный от ClassA. Все производные классы могут включать в себя CLASSA с #include "ClassA.h", если вы предоставите Стража в заголовке-файла, как это часто встречается в C++:

#ifndef ClassAH 
#define ClassAH 

... 

#endif 

Таким образом, заголовок будет включен только один раз ...

+0

Не уверен, но я думаю, что OP запросил параметр типа 'ClassB *'. –

+0

Было бы также возможно ... Я отредактировал его ... –

+0

Вы редактировали его между ними. 'ClassB *' не может использоваться в списке параметров без прямого объявления. –

1

Я заметил, ваша виртуальная функция ClassC объявлена ​​как не принимает никаких параметров:

virtual void action(); 

но вы определяете производный класс функцию с параметром.

void ClassC::action(ClassB * ptr) 

Декларация и определение должны соответствовать. Измените декларацию на:

virtual void action(ClassB *); 

Хм. Но тогда вы должны либо включить ClassB перед декларацией ClassC ...

#include "ClassB.h" 

или вперед объявить ClassB. Это обещание компилятору правильно объявить и определить класс позже. Хорошее место для вставки этой строки будет непосредственно перед объявлением ClassC.

class ClassB; 
+1

Ответ неплохой. Но как читатель должен знать, куда вставить форвардную декларацию? Пожалуйста, учтите, что ОП все еще изучает основы C++. –

+0

Отредактировано, чтобы предложить место для размещения декларации. Спасибо за помощь. :) –

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