#c #factory #abstract
#c #фабрика #аннотация
Вопрос:
У меня есть следующая абстрактная фабрика:
#include "MediaDevice.h"
class MediaFactory {
public:
MediaFactory();
virtual ~MediaFactory();
virtual MediaDevice * FMediaDevice (int type) = 0;
};
и следующей фабрике, которая наследуется от абстрактной факторизации:
#include "MediaFactory.h"
class JVCMedDevFactory : public MediaFactory {
public:
MediaDevice* FMediaDevice (int type) {
switch ((type_e)type) {
case CDPlayer_e:
return new JVCCdPlayer() ;
case DVDPlayer_e:
return new JVCVcrPlayer() ;
}
}
};
Мультимедийное устройство является :
#include <string>
#include <utility>
using namespace std;
class MediaDevice {
public:
MediaDevice();
virtual ~MediaDevice();
virtual void Start () = 0 ;
virtual void Stop () = 0 ;
virtual void Forward () = 0 ;
virtual void Rewind () = 0 ;
virtual pair <string,string> getName () const = 0;
protected:
pair <string,string> DeviceName;
};
Вот как я определяю проигрыватели JVC:
#include "MediaDevice.h"
#include <iostream>
using namespace std;
class JVCCdPlayer : public MediaDevice {
public:
JVCCdPlayer(){
DeviceName.first = "JVC";
DeviceName.second = "CD";
}
void Start (){
cout << "Playing " << this->getName().first << "," << this->getName().second << endl;
}
void Stop (){
cout << "Stopped " << this->getName().first << "," << this->getName().second <<endl;
}
void Forward (){
cout << "Rewind " << this->getName().first << "," << this->getName().second <<endl;
}
void Rewind (){
cout << "Forward " << this->getName().first << "," <<this->getName().second <<endl;
}
pair <string,string> getName () const{
return DeviceName;
}
~JVCCdPlayer(){}
};
И я получаю следующую ошибку
Возвращаемый тип не идентичен и не ковариантен возвращаемому типу «MediaDevice *» переопределенной виртуальной функции «MediaFactory :: FMediaDevice»
Важно, что в visula studio у меня есть красная строка под FMediaDevice в объявлении MediaDevice* FMediaDevice (int type) { в классе MedDevFactory. И не имеет значения, что я возвращаю. Я могу вернуть 0 и все равно получить ошибку.
Почему?
Комментарии:
1. Нам нужно увидеть определения
JVCCdPlayer
иJVCVcrPlayer
.2. Ошибка, по-видимому, указывает на то, что
MediaDevice
выполняется преобразование в два разных типа между определениемMediaFactory
иJVCMedDevFactory
. Используете ли вы прямые объявления в пространствах имен или что-то еще, что может привести к этому?3. Я добавил объявления JVCCdPlayer и JVCVcrPlayer
4. @sera: Опубликуйте также содержимое
"MediaDevice.h"
5. @Nawaz: Это уже есть. В разделе «Мультимедийное устройство — это:». Спасибо!
Ответ №1:
Из сообщения об ошибке кажется, что либо JVCCdPlayer
либо JVCVcrPlayer
(или оба) не являются производными от MediaDevice
. Это так?
Вы должны получить оба из MediaDevice
. Убедитесь, что ваши определения выглядят следующим образом:
class JVCCdPlayer : public MediaDevice
{
};
class JVCVcrPlayer : public MediaDevice
{
};
Или где-то в иерархии, MediaDevice
должен присутствовать.
Класс MediaDevice
имеет данные-члены DeviceName
, которые имеют тип pair<string,string>
, но вы не включили заголовок, в котором pair
определено. Поэтому включите <utility>
. Аналогичным образом, убедитесь, что вы включили все необходимые заголовки.
Кроме того, я бы не стал писать using namespace std
в заголовочном файле. Поэтому я бы переписал MediaDevice.h
как :
#ifndef MEDIA_DEVICE_H
#define MEDIA_DEVICE_H
#include <string>
#include <utility>
class MediaDevice
{
public:
MediaDevice();
virtual ~MediaDevice();
virtual void Start () = 0 ;
virtual void Stop () = 0 ;
virtual void Forward () = 0 ;
virtual void Rewind () = 0 ;
virtual std::pair<std::string,std::string> getName () const = 0;
private:
std::pair<std::string,std::string> DeviceName;
};
#endif
То есть я бы квалифицировал каждое имя с помощью std::
вместо using namespace std
.
Кстати, я не вижу определения следующей чисто виртуальной функции:
virtual pair <string,string> getName () const = 0;
Вы определили это в производных классах? (хотя в ошибке не говорится, что это проблема, но все равно убедитесь и в этом).
Кроме того, данные участника DeviceName
объявлены как, private
что и должно быть protected
, потому что вы обращаетесь к ним из производных классов JVCVcrPlayer
и JVCCdPlayer
.
Комментарии:
1. Из Visual Studio я вижу, что проблема связана с объявлением функции MediaDevice* FMediaDevice (тип int). Он помечает красной линией FMediaDevice. И для него не имеет значения, что я возвращаю. Я поставил retrun 0 и все равно увидел ошибку. Но JVCCDPlayer и JVCVcrPlayer также получены из MediaDevice. Что это значит «MediaDevice должно присутствовать.» ? Большое спасибо!
2. @sera: почему
pair
не требует заголовка? Кроме того, я предполагаю, что ваша программа выдает другую ошибку. Вы опубликовали все сообщения об ошибках?3. @Nawaz: Я предполагаю, что уже включенные заголовки неявно включают
<utility>
в Visual Studio.4. @Nawaz : Прошу прощения. Я проверил сейчас и действительно увидел другую ошибку: она помечена красной строкой под — return new JVCCdPlayer(); — и сказал, что объект типа абстрактного класса JVCCdPlayer не разрешен. Я полагаю, это произошло потому, что я изменил сегодня классы JvcCdPlayer и JVCVcrPlayer и удалил из них реализацию чисто виртуальных функций. Но все равно, даже если я не использую эти классы. Вместо этого возвращайте только 0. Первая ошибка, о которой я упомянул, все еще существует. Я использовал только #include <string>, используя std пространства имен; заголовки для пары
5. @sera: ДА. Я был прав. Это потому, что вы не определили
getName
чисто виртуальную функцию в производных классах. Всегда помните, что чисто виртуальные функции должны быть реализованы в производных классах!
Ответ №2:
MediaDevice, вероятно, не является родительским для JVCCdPlayer или JVCVcrPlayer.
Также обратите внимание, что функция JVCMedDevFactory::FMediaDevice не всегда гарантированно возвращает значение — у вас должен быть регистр по умолчанию в инструкции switch или возврат по умолчанию в нижней части функции.
Комментарии:
1. Большое спасибо вам за помощь, Как я уже сказал, я попытался оставить только одну строку — return 0 в реализации функции JVCMedDevFactory::FMediaDevice и все равно остался с ошибкой
Ответ №3:
После следующих изменений Visual Studio 2010 скомпилировала ваш код (хотя я поместил все это в один исходный файл).
- Включая все требуемые заголовки;
- Создание
MediaDevice::DeviceName
защищенного (не закрытого) члена, чтобы к нему могли обращаться конструкторы игровых классов; - Определение
type_e
как перечисление; - Удаление
=0
спецификатора «pure virtual» из объявленийMediaDevice
функций-членов и добавление очевидного определения для `MediaDevice::getName().
В реальном коде на последнем шаге вместо этого следовало бы добавить переопределяющие определения чисто виртуальных функций в классы проигрывателя, но мне было лень писать это.
Я должен сказать, что ни на одном этапе я не видел диагностики «Возвращаемый тип не идентичен и не ковариантен с».
Надеюсь, это поможет.
Комментарии:
1. Я полагаю, у меня проблема с «включением всех необходимых заголовков». Можете ли вы показать, как вы размещаете заголовки? Спасибо
2. @sera: Мне нужно было добавить
#include <iostream>
дляstd::cout
, и я также добавил#include <utility>
дляstd::pair
, хотя это неявно включено через какой-то другой заголовок VC.3. Спасибо за помощь. Я следовал инструкциям Nawaz, и это решило проблему. Но я считаю, что ваше решение также было хорошим.