2015-10-17 6 views
1

Допустим, у меня есть программа, в которой я хочу, чтобы решить уравнения (что-то вроде этого)указатели и ссылки + перегруженные операторы

Number x; 
Func fw = x * 4 + x * x; 
std::cout << fw(6.0) << "\n\n"; 

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

class Base 
{ 
public: 
    Base(){}; 
    virtual Base* operator*(Base& x) = 0; 
    virtual Base* operator*(double x) = 0; 
    virtual Base* operator+(Base& x) = 0; 
}; 

и класс Номер

class Number : public Base 
{ 
public: 
    virtual Base* operator*(Base& x); 
    virtual Base* operator*(double x); 
    virtual Base* operator+(Base& x); 
}; 

и класс Func с копией конструктора (или, по крайней мере, Ithink, что это конструктор копирования)

class Func: public Base 
{ 
    Base * func; 
public: 
    Func(Base* other) 
    { 
     func = other; 
    } 

    Func(Base& other) 
    { 
     func = &other; 
    } 

    virtual Base* operator*(Base& x){} 

    virtual Base* operator*(double x){} 

    virtual Base* operator+(Base&){} 

}; 

Итак, моя проблема. Моя программа работает для x*x или для x*4, но когда я пытаюсь их объединить x*x + x*4 У меня проблема.

Это очевидно (или это не так), в чем проблема. После x*x моя программа возвращает указатель (Base *), а в моих перегруженных операциях у меня есть только (Base &). Таким образом, программа не может сопоставить с ней какой-либо перегруженный оператор.

Вот что CLion показывает мне binary operator + can't be applied to the expression of type Base* and Base*

Таким образом, решение может быть перегрузка операторов еще раз, но с аргументом (Base *), но я надеюсь, что есть лучший способ решить эту проблему. Здесь?

+0

Основные типы данных не поддерживают, например, добавление float и int вместе. Вместо этого есть продвижение, int для плавания в этом случае. Возможно, вы можете решить проблему аналогичным образом. Продвигайте разные типы к одному типу, а затем выполните операцию. –

ответ

1

Да, есть: напишите класс-оболочку, который использует семантику значения или ссылки, а не семантику указателя. Например,

class BaseRep // I've renamed your `Base` class 
{ 
public: 
    BaseRep(){}; 
    virtual std::unique_ptr<BaseRep> multiply(const BaseRep& x) = 0; 
}; 

class Base 
{ 
    std::unique_ptr<BaseRep> ptr; 
public: 
    Base(std::unique_ptr<BaseRep> &&p):ptr(p) {} 
    BaseRep& rep() { return *ptr; } 
    const BaseRep& rep() const { return *ptr; } 
    // and other stuff 
}; 

Base operator*(const Base &x, const Base &y) 
{ 
    return Base(x.rep().multiply(y.rep())); 
} 
+0

Вам не нужен виртуальный деструктор? –

+0

@Neil: Да; этот пример не был полной библиотекой, а просто демонстрацией основ идеи. (также, я виню тот факт, что я копирую-пасту редактирую из сообщения OP) – Hurkyl

0

все арифметические операторы должны возвращать ссылку (или копию), абсолютно не указатель.

+2

Возврат на куски фрагмента; возвращаясь по эталонным утечкам (или зависает). Реальный ответ: «этот дизайн полностью сломан». –

+1

@ T.C. Я с тобой согласен. Тем не менее, я должен написать эту программу следующим образом: C –

+1

легко исправить. полиморфная концепция должна принадлежать классу неполиморфных дескрипторов. Затем добавьте метод клона в полиморфную концепцию и реализуйте копии в терминах этого. Тогда, конечно, вам понадобятся некоторые способы разрешения динамической отправки, когда добавляются два несходных объекта .... или вы можете использовать 'boost :: variant'. –

0
template < size_t Index > 
struct placeholder { 
    template < typename ... Args > 
    auto operator()(Args ... args) const 
    { 
     auto tpl = std::make_tuple(args...); 
     return get<Index>(tpl); 
    } 

}; 

placeholder<0> _1; 
placeholder<1> _2; // etc... 

template < typename T > 
struct val 
{ 
    T value; 
    val(T v) : value(v) {} 

    template < typename ... Args > 
    auto operator()(Args ...) const { return value; } 
}; 

template < typename LH, typename RH > 
struct plus_operator 
{ 
    plus_operator(LH l, RH r) : lh(l), rh(r) {} 

    LH lh; 
    RH rh; 

    template < typename ... Args > 
    auto operator()(Args ... args) const { return lh(args...) + rh(args...); } 
}; 

template < size_t I, typename T > 
auto operator + (placeholder<I> lh, T rh) 
{ 
    return plus_operator<placeholder<I>,T>{lh,val<T>{rh}}; 
} 
template < typename T, size_t I > 
auto operator + (T lh, placeholder<I> rh) ... 
// because this would otherwise be ambiguous... 
template < size_t I1, size_t I2 > 
auto operator + (placeholder<I1> lh, placeholder<I2> rh) ... 

же же для *, -,/...

auto fun = _1 * 4 + _1 * _1; 

auto result = fun(5); 

Не тестировалось. Нет гарантий. Но этот метод я верю, что вы хотите решить проблему. Он называется «шаблоны выражений».

О, и вам придется переопределить для каждого возможного оператора LH, RH ... возможно, лучший способ использования SFINAE.

Смежные вопросы