Подтвердить что ты не робот

С++ Аннотация проблема перегрузки и перегрузки интерфейса оператора

(отредактировано с исходного сообщения, чтобы изменить "BaseMessage" на "const BaseMessage &" )

Привет всем, Я очень новичок в С++, поэтому, надеюсь, вы, люди, можете мне помочь "увидеть ошибки моих путей".

У меня есть иерархия сообщений, и я пытаюсь использовать абстрактный базовый класс для обеспечения соблюдения интерфейс. В частности, я хочу заставить каждое полученное сообщение обеспечить перегрузку & Л; < Оператор.

Когда я пытаюсь сделать это с чем-то вроде этого:

class BaseMessage
{
public:

// some non-pure virtual function declarations
// some pure virtual function declarations

virtual ostream& operator<<(ostream& stream, const BaseMessage& objectArg) = 0;

}

компилятор жалуется, что

"error: не может объявлять параметр objectArg абстрактного типа BaseMessage

Я считаю, что здесь есть и "друг", но когда я пытался объявить его как:

virtual friend ostream& operator<<(ostream& stream, const BaseMessage objectArg) = 0;

компилятор добавил ошибку с добавлением

": виртуальные функции не могут быть друзьями"

Есть ли способ гарантировать, что все мои производные (сообщения) классы предоставляют "< < операционный оператор?

Большое спасибо,

Стив

4b9b3361

Ответ 1

Общим соглашением для этого является наличие оператора вывода friend на базовом уровне и вызов его частной виртуальной функции:

class Base
{
public:

    /// don't forget this
    virtual ~Base();

    /// std stream interface
    friend std::ostream& operator<<( std::ostream& out, const Base& b )
    {
        b.Print( out );
        return out;
    }

private:

    /// derivation interface
    virtual void Print( std::ostream& ) const =0;
};

Ответ 2

Абстрактный класс не может быть создан, поэтому выполните следующее:

virtual ostream& operator<<(ostream& stream, const Base &objectArg) = 0; 

Виртуальная функция должна быть функцией-членом экземпляра, тогда как функция friend является функцией, не являющейся членом, поэтому ее нельзя объявить виртуальной.

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

Мое предложение:

class Base {
 public:
 virtual ostream&  print (ostream& stream) const = 0; 
};


class Derived :public Base {
 public:
 virtual ostream&  print (ostream& stream) const { //do something } 
};

ostream& operator <<(ostream& stream, const BaseMessage &objectArg) 
{
  return objectArg.print(stream); 
}

Ответ 3

Операторы потока, такие как:

virtual ostream& operator<<(ostream& stream, const BaseMessage objectArg) = 0;

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

a << b;

ты действительно говоришь

a.operator<<( b );

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

Ответ 4

Объявление для оператора < (lt) неверно. Для двоичной версии op <, вам не нужно объявлять второй параметр - предполагается, что это this, если op < < является функцией-членом класса:

virtual ostream& operator<<(ostream& stream) = 0;

Кроме того, как упоминалось другими, операторы вставки потока должны быть глобальными функциями. Их функции-члены просто не работают.

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

#include <cstdio>
#include <string>
#include <iostream>
using namespace std;

class Base 
{
public:
    virtual void dump() 
    {
        cout << "Base";
    };
};

class Der : public Base
{
public:
    void dump()
    {
        cout << "Der";
    };
};

void DumpIt(Base b)
{
    b.dump();
}


int main() 
{
    Der obj;
    DumpIt(obj);
    return 0;

}

... и ожидая, что вывод будет "Der". Но на самом деле выход "Base" из-за Object Slicing. Поскольку функция DumpIt() принимает объект Base по значению, создается новый временный базовый объект на основе оригинала. Чтобы получить функциональность, которую вы ожидали, вам нужно пройти по ссылке или указателем:

void DumpIt(Base & b)
{
    b.dump();
}

Выход из этой функции - "Der".

Ответ 5

Проблема заключается в том, что "ObjectArg BaseMessage" говорит, что объект objectArg должен быть передан по значению.

Это невозможно, так как вы сделали абстрактную категорию с помощью своего чистого виртуального вызова. Передача по ссылке "BaseMessage & objectArg" или проход по указателю "BaseMessage * objectArg" заставят эту ошибку уйти.

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