Вывод из класса с перегрузкой оператора - PullRequest
2 голосов
/ 14 апреля 2009

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

Моей первоначальной идеей для реализации этого было создание базового класса Rn с перегрузками, а затем создание производных классов с красивыми именами. Примерно так:

#include <iostream>
#include <algorithm>
using namespace std;

template<int N, class X=double>
struct Base{
    X xs[N];

    Base(){};

    Base(X *data){
        copy(data, data+N, xs);
    }

    Base operator*= (double d){
        for(int i=0; i<N; i++){
            xs[i] *= d;
        }
        return *this;
    }

    Base operator* (double d){
        Base answer = *this;
        answer *= d;
        return answer;
    }

    //also operators for +=, +, multiplication from left, maybe [] too
};

struct Derived : public Base<2>{
    Derived(double a, double b){
        foo() = a;
        bar() = b;
    }

    double &foo(){ return xs[0]; }
    double &bar(){ return xs[1]; }
};

int main()
{
    //this is OK:
    double data[2] = {0.0, 2.0};
    Base<2> b(data);
    b = b*17.0;

    cout << b.xs[0] << endl;

    //I can't do this:
    Derived x(0.0, 2.0);
    x = x*17.0;

    cout << x.foo() << endl;

    return 0;
}

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

teste.cpp: In function ‘int main()’:
teste.cpp:52: error: no match for ‘operator=’ in ‘x = x.Derived::<anonymous>.Base<N, X>::operator* [with int N = 2, X = double](1.7e+1)’
teste.cpp:31: note: candidates are: Derived& Derived::operator=(const Derived&)

Мне кажется, проблема в том, что функции перегрузки имеют дело с объектами Base, которые не могут быть преобразованы в производные, поэтому я не могу использовать их в производном классе. Однако я не могу придумать решение. Есть ли способ обойти это или я должен использовать совершенно другой подход?

Дополнительный вопрос: есть ли способ, с помощью которого я могу использовать std :: valarray, чтобы избежать необходимости набирать много и много перегрузок операторов?

Ответы [ 5 ]

3 голосов
/ 14 апреля 2009

Ваши операторы Base (* в данном случае) могут принимать производный объект, но они возвращают базовый объект, который нельзя использовать в качестве правого операнда в операторе назначения производного по умолчанию. Самый простой способ это исправить - просто добавить оператор присваивания в Derive, который будет принимать значение Base:

Derived& operator= (const Base<2>& other)

Вам нужно будет добавить его к любому производному классу, но реализация довольно проста (вы можете иметь функцию void CopyOtherBase, которая будет выполнять копирование, и иметь все операторы = вызвать ее и вернуть * это).

2 голосов
/ 14 апреля 2009

Я рассмотрю только технические трудности, неважно, хорошая это идея или нет.

Проблема в том, что результатом оператора * Derived является Base, а operator = Derived (который является оператором по умолчанию =) не знает, как "съесть" Base.

Простое решение - создать конструктор Derived, который получает Base и делает все необходимое для правильной инициализации. Это позволило бы на лету преобразовать базу в производное - и сработало бы для всех других операторов Derived, которые ожидают базу.

Что-то вроде -

Derived(const Base<2>& B) : Base<2>( B )
{
}
1 голос
/ 14 апреля 2009

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

например, static const int FIELD_NAME = 0;
Статическая константа int FIELD_NAME2 = 1;

чем делать это как разные типы (шаблоны). Затем вы можете использовать типы std :: valarray или boost :: ublas :: vector / matrix, чтобы использовать существующий код и получать качественные векторные операции производительности для загрузки.

0 голосов
/ 14 апреля 2009

Согласно MSDN ,

Все перегруженные операторы, кроме присваивание (оператор =) наследуется по производным классам.

Может ли это быть вашей проблемой?

0 голосов
/ 14 апреля 2009

Шаблонное метапрограммирование имело интересную идею по решению именно такого рода проблем с математическими векторами, но, возможно, не решило вашу проблему именования частей.

Дэвид Абрахамс, Алексей Гуртовой: Метапрограммирование шаблонов на C ++: концепции, инструменты и методы от Boost и Beyond, Addison-Wesley, ISBN 0-321-22725-5

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