C ++ Наследование с чисто виртуальными функциями - PullRequest
4 голосов
/ 15 мая 2011

Я пытаюсь создать класс, который будет служить базовым объектом, который затем будет разделен на подклассы (= реализован) для различных целей.

Я хочу определить одну или несколько чисто виртуальных функций, чтобы, однако, подклассы базового класса были обязательными и не забывали их реализовывать.

Существует одно предупреждение: сигнатура чисто виртуальной функции включает тип базового объекта. Разумеется, после подкласса определение функции больше не соответствует определению базовых классов. E.g.:

class BaseItem 
{
public:
    virtual std::string getDifferences(const BaseItem& item) = 0;
}

Итак, в производном классе я хотел бы сделать:

class DerivedClass : public BaseItem
{
public:
    virtual std::string getDifferences(const DerivedClass& item) = 0;
private:
    std::string derivedItemCustomObject;
}

, что, конечно, компилятор не примет. Конечно, я мог бы сделать это BaseItem, но тогда я не смогу использовать какие-либо объекты в производном классе.

Должен ли я использовать кастинг, чтобы выполнить это?

Пожалуйста, дайте мне знать, если мое намерение / вопрос не ясен.

Ответы [ 5 ]

4 голосов
/ 15 мая 2011

НЕТ необходимости менять сигнатуру функции . Посмотрите на следующее:

class BaseItem 
{public:
    virtual std::string getDifferences(const BaseItem& item) = 0;
};

class DerivedClass : public BaseItem
{public:
    virtual std::string getDifferences(const BaseItem& item)  // keep it as it's
    {
       const DerivedClass& derivedItem = static_cast<const DerivedClass&>(item);
    }
};

Может использовать static_cast<> без какого-либо страха, потому что DerivedClass::getDifferences() вызывается только для DerivedClass объекта. Для иллюстрации

BaseItem *p = new DerivedClass;
DerivedClass obj;
p->getDifferences(obj);  // this always invoke DerivedClass::getDifferences

Если вы беспокоитесь о том, что когда-нибудь вы можете передать любой другой объект производного класса в качестве аргумента методу, используйте вместо него dynamic_cast<> и выведите исключение, если произойдет сбой.

2 голосов
/ 15 мая 2011

Я предполагаю, что компилятор принимает, но DerivedClass :: getDifferences не переопределяет BaseItem :: getDifferences. Вот способ достичь того, что вы, очевидно, хотите

template <typename T>
class DerivedHelper: public BaseItem {
public:
   virtual std::string getDifferences(const BaseItem& item) {
      getDifferences(dynamic_cast<const T&>(item));
   }
   virtual std::string getDifferences(const T& item) = 0;
}; 

class DerivedClass : public DerivedHelper<DerivedClass>
{
public:
   // not more needed but providing it will hide getDifferences(const BaseItem& item)
   // helping to statically catch some cases where a bad argument type is used.
   virtual std::string getDifferences(const DerivedClass& item) = 0;
private:
   std::string derivedItemCustomObject;
};

но имейте в виду, что существует проверка во время выполнения, которая будет выдавать исключения, если аргумент не соответствует классу.

2 голосов
/ 15 мая 2011

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

class BaseItem 
{
public:
    virtual std::string getDifferences(const BaseItem& item) = 0;
};

class DerivedClass : public BaseItem
{
public:
    virtual std::string getDifferences(const DerivedClass& item) 
    {
        item.f(); 
        // ... 
    }

    void f() const {}
};

class DerivedClass2 : public BaseItem
{
public:
    virtual std::string getDifferences(const DerivedClass2& item) { ... }
};

void g()
{
    BaseItem* x = new DerivedClass;

    // oops, calls DerivedClass::f on an instance of DerivedClass2
    x->getDifferences(DerivedClass2());
}

Ваш дизайн, вероятно, неправильный.

1 голос
/ 15 мая 2011

Один из способов сделать это - использовать шаблон, указав в качестве параметра тип производного типа

template <typename T>
class BaseItem {
public:
  virtual std::string getDifferences(const T& item) = 0;
};

class DerivedClass : public BaseItem<DerivedClass> {
public:
  virtual std::string getDifferences(const DerivedClass& item) {
    // Implement it here
  }
};
0 голосов
/ 15 мая 2011

Вы должны использовать приведение из BaseItem к DerivedClass + проверка времени выполнения, если данный BaseItem является экземпляром DerivedClass.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...