наследование — c ++: наследование метода с другим (но ковариантным) типом возвращаемого значения

Предположим, у нас есть 2 класса:

class DataStructure {
public:
DataStructure &operator=(const DataStructure &);
friend const DataStructure &operator+(int, const DataStructure &);
//...
};

class Array : public DataStructure {
public:
Array &operator=(const DataStructure &);
friend const Array &operator+(int, const Array &);
//...
};

и мы хотим Array::operator= а также Arrayдрузья operator+ сделать то же самое, что и DataStructure::operator= а также DataStructureдрузья operator+кроме того, что они должны вернуться Array &,const Array & вместо DataStructure &,const DataStructure &, Мне нужно сделать это с помощью десятков методов, поэтому есть ли более простой способ реализовать это, чем следующие?

Array &Array::operator=(const DataStructure &other) {
return (Array &)DataStructure::operator=(other);
}

const Array &operator+(int x, const Array &other) {
return (const Array &)(x + (DataStructure)other);
}

РЕДАКТИРОВАТЬ: У меня появилась другая идея, хотя она довольно плохая:

class Array;

class DataStructure {
public:
//...
operator Array &() const;
};
//...
DataStructure::operator Array &() const {
return (Array &)*this;
}

Сюда DataStructure неявно преобразуется в Array когда это необходимо, хотя он по-прежнему не может правильно обрабатывать случаи, когда оба DataStructure а также Array являются законными, но делают разные вещи, как в этом примере:

//in class DataStructure:
public:
friend ostream &operator<<(ostream &os,const DataStructure &)
{ os << "DataStructure" << endl; return os;}
//in class Array:
public:
friend ostream &operator<<(ostream &os,const Array &)
{ os << "Array" << endl; return os;}
//...
int main() {
Array x;
cout << 1 + x << endl;
// output: "DataStructure" instead of "Array"
return 0;
}

Спасибо вам!

1

Решение

Ваша реализация не хороша: operator= должен возвращать ссылку на объект типа Array, и не должен быть виртуальным:

Array &Array::operator=(const DataStructure &other) {
DataStructure::operator=(other);
return *this;
}

Ты можешь измениться DataStructure использовать NVI :

#include <iostream>

class DataStructure {
public:
DataStructure(){}
inline virtual ~DataStructure(){}
DataStructure &operator=(const DataStructure & other);
inline friend const DataStructure &operator+(const int a, const DataStructure & other)
{ other.add(a); return other; }
//...
private:
virtual void add( const int a ) const = 0;
};
struct Array : DataStructure
{
virtual void add( const int a ) const
{
std::cout<<"adding "<<a<<std::endl;
}
};

void foo(const DataStructure &a)
{
const DataStructure &b = 5 + a;
}

int main()
{
Array a;
foo(a);
}

Проверьте живое демо. Затем вы должны реализовать метод add в вашем производном классе Array.


Для вашего редактирования:

Ваша новая идея — ужасный способ делать вещи в C ++. То, что вы там делаете, говорит вашему компилятору: «Хватит жаловаться, я знаю, что делаю». Кроме того, это вызывает неопределенное поведение. Может показаться, что работает, пока приложение не начнет сбой один день.

1

Другие решения

В конце концов мне удалось найти ответ. За operator=:

class Array : public DataStructure {
public:
//...
using DataStructure::operator=;
Array &operator=(const DataStructure &);
};

Только написание Array &operator=(const DataStructure &); будет прятаться DataStructure::operator=, но с using заявление это только меняет тип возвращаемого значения метода.

Замечания: using оператор должен предшествовать строке Array &operator=(const DataStructure &);, иначе operator= было бы неоднозначно.


Что касается operator+Единственное решение, которое я нашел, очень проблематично. Он использует шаблоны:

public DataStructure {
public:
template<class T> friend const T &operator+(int, const T &);
};

Например, если оригинальная реализация была

const DataStructure &operator+(int x, const DataStructure &other) {
DataStructure addition(other); /* in this example we assume
*   that "DataStructure" isn't abstract */
addition.someParameter += x; /* for simplicity, assume that
*   "someParameter" is public/protected */
return addition;
}

и мы хотим добиться того же результата, что и в

const Array &operator+(int x, const Array &other) {
return (const Array &)(x + (DataStructure)other);
}

чем мы можем просто написать:

template<class T>
const T &operator+(int x, const T &other) {
DataStructure addition(other); /* notice that usually we would want
*   to write "T" instead of "DataStructure", but sometimes it would
*   give a different result */
addition.someParameter += x;
return (const T &)addition;
}

Однако, если существует функция operator+(int,/*const*/ ThirdClass /*&*/) это не имеет ничего общего с DataStructure или же Array чем мы должны были бы изменить это, что могло бы испортить код. К счастью, обычно есть только несколько дружественных функций, поэтому реализация нового метода, который выполняет преобразование (как показано в вопросе), не так уж плоха.

0

По вопросам рекламы [email protected]