Inheritance of overloaded + operator - c++

I have a problem in inheriting overloaded + operator.
Let me make an example.
class Data{
protected:
int data[3];
public:
Data(){
data[0] = data[1] = data[2] = 0;
}
Data operator+(const Data& other)
{
Data temp = *this;
for(int i=0;i<3;i++){
temp.data[i] += other.data[i]
}
return temp;
}
};
class DataInterited:public Data{
public:
};
/******************Main*****************/
DataInterited d1,d2,d3;
d3 = d1 + d2; //=> This is compile error
This code generate compile error saying,
no match for ‘operator=’ (operand types are ‘DataInterited’ and ‘Data’)
I think I have to implement operator+ for DataInherited so that it return DataInherited instance. But in this way, I cannot avoid code duplication.
Is there any way to make d3=d1+d2; line correct while avoiding duplicating the + operator implementation?

There are a couple of things you need to know.
First, always implement operator+ as a free function in terms of operator+=. It saves code duplication and is optimally efficient.
Second, you had no constructor in DataInherited that could take a Data as its argument. This is important because the result of Data::operator+ is a Data, not a DataInherited.
corrected code:
#include <iostream>
#include <algorithm>
class Data{
protected:
int data[3];
public:
Data(){
data[0] = data[1] = data[2] = 0;
}
Data(const Data& other)
{
std::copy(std::begin(other.data), std::end(other.data), data);
}
Data& operator=(const Data& other)
{
std::copy(std::begin(other.data), std::end(other.data), data);
return *this;
}
Data& operator+=(const Data& other)
{
for(int i=0;i<3;i++){
data[i] += other.data[i];
}
return *this;
}
};
Data operator+(Data left, const Data& right)
{
return left += right;
}
class DataInterited:public Data{
public:
DataInterited(Data d = {})
: Data(std::move(d))
{}
};
using namespace std;
auto main() -> int
{
DataInterited d1,d2,d3;
d3 = d1 + d2; //=> This is no longer a compile error
return 0;
}

Koenig operator forwarding to an increment_by function.
Derived classes can implement their own increment_by overloads if they want different behavior.
SFINAE stuff skipped, so bad types will give hard errors.
class Data{
public:
template<class D, class Rhs>
friend D operator+=(D&& lhs, Rhs&& rhs){
increment_by(lhs,std::forward<Rhs>(rhs));
return std::forward<D>(lhs);
}
template<class Lhs, class Rhs>
friend Lhs operator+(Lhs lhs, Rhs&& rhs){
lhs+=std::forward<Rhs>(rhs);
return std::move(lhs);
}
friend void increment_by(Data& self, Data const&other){
for(int i=0;i<6;i++){
self.data[i] += other.data[i];
}
}
};
Both + and += are template friends and hence the types passed can be derived classes. So type isn't lost,
increment_by needs overiding if derived type needs new behaviour. If not, leave it alone.
live example.
Do not leave the type needlessly. Converting from base to derived basically throws out the point of the derived type.

Related

derived class reusing base class operations

I have a large class, Base, that implements several different binary operations, some overloading the operators like *=, *, / etc, and some extra ones. The typical return type involves Base explicitly, for example:
class Base {
private:
std::vector<unsigned int> _arr;
public:
// These operations do something with _arr
Base& operator *= (const Base& rhs);
friend Base operator *(Base lhs, const Base& rhs);
std::vector<Base> myoperation(const Base& rhs);
};
I have a derived class, Derived, which simply adds extra structure, so it looks like this:
class Derived : public Base {
private:
std::vector<int> _arr_derived;
public:
// This operation does something with _arr and _arr_derived;
Derived& my_derived_operation(const Derived& rhs);
// These operations are exactly the same implementation as the one in Base!
Derived& operator *= (const Derived& rhs) {
Base::operator*=(rhs);
return *this;
}
friend Derived operator *(Derived lhs, const Derived& rhs) {
lhs *= rhs;
return lhs;
}
std::vector<Derived> myoperation(const Derived& rhs) // <---- what to do here?
};
What do I need to do with the operation myoperation? That returns a vector. There is no extra logic on all operations that are inherited, the only difference is in the return type. Is there any way to avoid the code duplication? Even the declaration of the operations is bothersome.
I thought perhaps defining the base operations as template functions returning the same type as the argument, and requiring the template parameter to be a derived class:
class Base {
// on C++20
template<class C> requires std::is_base_of_v<Base,C>
C& operator*=(const C& rhs);
}
Does this work? Even if it does, is there a better mechanism?
Edit to reply to Remy Lebeau's comment: I want to emphasize that all operations that appear both in Derived and in Base are meant to be the same, there is not extra logic except the returning type. The example of operator *= already shows this, just calling the Base version. A possible implementation, albeit stupid, of what I mean by myoperation could be this:
std::vector<Base> Base::myoperation(const Base& rhs) {
std::vector<Base> ret{};
ret.push_back(rhs*rhs);
return ret;
}
std::vector<Derived> Derived::myoperation(const Derived& rhs) {
std::vector<Derived> ret{}
ret.push_back(rhs*rhs);
return ret;
}
With the templated version I could write only
class Base {
teplate<class C> requires std::is_base_of_v<Base,C>
auto myoperation(const C& rhs) {
std::vector<C> ret;
ret.push_back(rhs*rhs);
return ret;
}
};
And that's what I meant by the templated solution above, so that I do not need to even declare myoperation on Derived.
I went with the templated version, although using pointers is standard in polymorphism, I have too many vector valued operations and are complicated enough to change the logic, and also wouldn't want to have to deal with recasting to Derived classes when necessary. Templating also has the advantage that no code needs to be written on the derived classes. So on base all operations that transform the object in place are left as they were and the ones that produce new ones are templated. I appreciate if I could be pointed to pitfalls of this approach
#include <iostream>
#include <vector>
class Base {
int _a;
public:
Base(int a) : _a{a} {};
Base& operator *= (const Base& rhs) {
_a *= rhs.a();
return *this;
}
template <class C> requires std::is_base_of_v<Base,C>
friend C operator *(C lhs, const Base& rhs) {
lhs *= rhs;
return lhs;
}
template <class C> requires std::is_base_of_v<Base,C>
std::vector<C> myop (const C& rhs) {
std::vector<C> ret {};
ret.push_back(rhs*rhs);
return ret;
}
int a() const { return _a; }
};
class Derived : public Base {
int _b;
public:
Derived(int a, int b) : Base{a}, _b {b} {}
int b() const {return _b;}
};
int main() {
Derived C{9,5};
Derived D{4,7};
auto E = C*D;
auto F = D.myop(C);
std::cout << E.a() << ", " << E.b() << std::endl;
std::cout << F.front().a() << ", " << F.front().b() << std::endl;
return 0;
}
OUTPUT:
36, 5
81, 5

C++ What operators I need to overload to make this A1 += A2 * floatValue work?

What operators I need to overload to make this word?
Variables A1 and A2 both of type class A, variable floatValue is of type float.
A1 += A2 * floatValue;
I have overloaded this operators
A operator+() const;
A operator+=(const A value);
A operator*(const A value);
friend A operator*(const A val2, float val);
But, I receive error "Class A has no suitable copy constructor"
I have this constructors in my class
A();
A(float val1, float val2);
A(float value);
Thanks for answering.
Minimal example:
#include <iostream>
using namespace std;
struct foo {
float val;
foo(float val): val(val){}
foo &operator+=(foo const &other) {
this->val += other.val;
return *this;
}
friend foo operator*(foo const &lhs, foo const &rhs) {
return lhs.val*rhs.val;
}
};
int main() {
foo a = 5, b = 6;
a += b * 3;
cout << a.val << endl;
return 0;
}
see: http://ideone.com/6pD2pr
With an explicit constructor you might want to use this example instead:
#include <iostream>
using namespace std;
struct foo {
float val;
explicit foo(float val): val(val){}
foo &operator+=(foo const &other) {
this->val += other.val;
return *this;
}
friend foo operator*(foo const &lhs, float val) {
return foo(lhs.val*val);
}
};
int main() {
foo a(5), b(6);
a += b * 3;
cout << a.val << endl;
return 0;
}
see: http://ideone.com/o8Vu1d
Whenever you overload an assignment operator like
A operator+=(const A value);
you also need to define a copy constructor like
A( const A& );
The copy constructor will be used by the assignment operator.
This is part of what's known as the Rule of Three.
When you have function like this:
fun(A a);
Arguments here are passed by value, so you need to have copy constructor for A (in order to create new instance from another instance), OR you can change it to reference, so no copy constructor will be needed.
Like this:
A operator+=(const A &value);

Efficient vector operators in C++ / References to temporary objects

I am trying to write a C++ vector class that stores an array of data and allows performing mathematical operations on an element-by-element basis. I want to implement this in such a way that an expression a = b + c + d should loop over all elements only once and directly write the sum b[i] + c[i] + d[i] to a[i] without creating intermediate vectors.
I was writing something like this:
template<class T, int N>
class VectorExpression {
public:
virtual T operator[] (int i) const = 0;
virtual ~VectorExpression() {}
}
template<class T, int N>
class MyVector : public VectorExpression<T, N> {
T data[N];
public:
T& operator[] (int i) { return data[i]; }
T& const operator[] (int i) const { return data[i]; }
MyVector<T,N>& operator=(const VectorExpression<T,N> &rhs) {
for (int i = 0; i < N; ++i)
data[i] = rhs[i];
return *this;
}
}
template<class T, int N>
class VectorSum : public VectorExpression<T, N> {
VectorExpression<T,N> &a, &b;
public:
VectorSum(VectorExpression<T,N> &aa, VectorExpression<T,N> &bb)
: a(aa), b(bb) {}
T operator[] (int i) const { return a[i] + b[i]; }
}
template<class T, int N>
VectorSum<T,N> operator+(const VectorExpression<T,N> &a,
const VectorExpression<T,N> &b)
{
return VectorSum<T,N>(a, b);
}
int main() {
MyVector<double,10> a, b, c, d;
// Initialize b, c, d here
a = b + c + d;
return 0;
}
Probably this functionality is provided by the valarray class but that's because I tried to strip it down to a minimal example.
I made operator[] virtual because this allows nesting all kinds of expressions (e.g. a = !(-b*c + d)) provided I would define all the operators and the corresponding classes similar to VectorSum.
I use references because ordinary variables aren't polymorphic and pointers don't work with operator overloading.
Now my questions about this are:
In the statement a = b + c + d;, two temporary VectorSum<double,10> objects will be created to store b + c and (b+c) + d respectively. Will they live long enough to make the polymorphic behavior work? More specifically, (b+c) + d will store a reference to b + c, but will that object still exist when operator= is called? According to this post all temporaries should exist until operator= returns, but does this also hold for older versions of C++?
If not, then how is this done? The only alternative I see would be to allocate the VectorSum objects using new, return them by reference and then delete them in the operator= functions, but that seems a little cumbersome, and probably a lot less efficient. I'm also not sure if it is always safe.
(Minor question) Is it okay to override the return type T of VectorExpression::operator[] by T& const in MyVector?
EDIT
I had wrong argument types in operator+: changed them from VectorSum to VectorExpression.
Well here's what I came up with:
#include <iostream>
#include <initializer_list>
#include <algorithm>
template<class T, int N>
class VectorExpression {
public:
virtual T operator[] (int i) = 0;
virtual const T operator[] (int i) const = 0;
virtual ~VectorExpression() {}
};
template<class T, int N>
class MyVector : public VectorExpression<T, N> {
T data[N];
public:
MyVector() {
// initialize zero
std::fill(std::begin(data), std::end(data), T());
}
MyVector(const std::initializer_list<T>& values) {
// initialize from array initializer_list
std::copy(std::begin(values), std::end(values), data);
}
MyVector(const VectorExpression<T,N>& rhs) {
for (int i = 0; i < N; ++i)
data[i] = rhs[i];
}
MyVector<T,N>& operator=(const VectorExpression<T,N>& rhs) {
for (int i = 0; i < N; ++i)
data[i] = rhs[i];
return *this;
}
T operator[] (int i) { return data[i]; }
const T operator[] (int i) const { return data[i]; }
friend std::ostream& operator<<(std::ostream& stream, MyVector& obj) {
stream << "[";
for (int i = 0; i < N; ++i) {
stream << obj.data[i] << ", ";
}
stream << "]";
return stream;
}
};
template<class T, int N>
class VectorSum : public VectorExpression<T, N> {
const MyVector<T,N> &a, &b;
public:
VectorSum(const MyVector<T,N>& aa, const MyVector<T,N>& bb):
a(aa), b(bb) {
}
T operator[] (int i) { return return a[i] + b[i]; }
const T operator[] (int i) const { return a[i] + b[i]; }
};
template<class T, int N>
MyVector<T,N> operator+(const MyVector<T,N>& a, const MyVector<T,N>& b) {
return VectorSum<T,N>(a, b);
}
int main() {
MyVector<double,3> a, b({1,2,3}), c({3,4,5}), d({4,5,6});
a = b + c + d;
std::cout << b << std::endl;
std::cout << c << std::endl;
std::cout << d << std::endl;
std::cout << "Result:\n" << a << std::endl;
return 0;
}
Output:
[1, 2, 3, ]
[3, 4, 5, ]
[4, 5, 6, ]
Result:
[8, 11, 14, ]
I've added an initializer_list (C++11) constructor and ostream operators purely for convenience/illustration purposes.
Since you've defined the operator[] as return by value, I was unable to set items in the data array for testing (since error: lvalue required as left operand of assignment); typically this operator should be by reference - but then, in your case, VectorSum::operator[] wouldn't work because that would fail compilation because of returning a reference to a temporary.
I also added a copy constructor because ...
// this calls MyVector's copy constructor when assigned to 'main::a'
template<class T, int N>
MyVector<T,N> operator+(const MyVector<T,N>& a, const MyVector<T,N>& b) {
return VectorSum<T,N>(a, b); // implicit MyVector::copy constructor
}
// this also calls MyVector's copy constructor (unless the copy constructor is defined explicit)
template<class T, int N>
MyVector<T,N> operator+(const MyVector<T,N>& a, const MyVector<T,N>& b) {
MyVector<T,N> res = VectorSum<T,N>(a, b);
return res;
}
// but this would call MyVector's assignment operator
template<class T, int N>
MyVector<T,N> operator+(const MyVector<T,N>& a, const MyVector<T,N>& b) {
MyVector<T,N> res;
res = VectorSum<T,N>(a, b);
return res;
}
In answer to your questions:
Yes - how would it behave if you explicitly defined the variable and
returned that? It's the same behaviour for temporaries, except there
is no variable declaration;
n/a
I touched on this above - you can't
use reference because of 'returning reference to temporary' error;
However there's no reason why you can add T& operator[] to MyVector( ie. not overriding).
EDIT: answers to comments:
The function specification must be identical when overriding including return type. Since you have defined it return by value in VectorExpression it must be return by value in MyVector. If you try to change it to reference in the child class you will get a compile error: conflicting return type specified. So no you can't override operator const with a version that returns const T& instead of T. Furthermore it must return by value since MyVectorSum returns { a[i] + b[i] } which would be a temporary and you can't return a reference to a temporary.
Sorry my mistake, fixed above.
because:
MyVector isn't a subtype of VectorSum - compile error ‘MyVector’ is not derived from ‘const VectorSum’
I've also tried with VectorExpression but compile error: 'cannot allocate an object of abstract type' - because it's trying to return by value
I chose MyVector since that's the type of your expected result. Yes it does those all those for loops but I can't see a way round that : there's three different array 'data' variables each of which need to be iterated into order to be accumulated. At some point in the code you will have to do the for loops.
Understood, yes I got confused. removed from post.
I didn't think of this at first but having a virtual operator[] method probably kills the efficiency I was trying to achieve by avoiding the 3 for-loops and intermediate storage of vector-sized temporaries. Making a method virtual prevents it from being inlined, which means it needs to be actually called as a function everytime an element is accessed.
Based on links I got from people who commented to my question and from Google, I ended up with the following solution which avoids needing any virtual methods.
template<class T, int N, class V>
class VectorExpressionBase {
V ref;
protected:
explicit VectorExpressionBase(const V *ref)
: ref(const_cast<V*>(ref)) {}
public:
T operator[] (int i) const { return ref[i]; }
T& operator[] (int i) { return ref[i]; }
};
template<class T, int N>
class VectorExpressionBase<T,N,void> {
T data[N];
protected:
explicit VectorExpressionBase(const void*) {
// Argument is unused but accepted to have uniform
// calling syntax
}
public:
T operator[] (int i) const { return data[i]; }
T& operator[] (int i) { return data[i]; }
};
template<class T, int N, class V>
class VectorExpression : public VectorExpressionBase<T,N,V> {
public:
template<class V1>
VectorExpression<T,N,V>& operator= (
const VectorExpression<T,N,V1> &rhs)
{
for (int i = 0; i < N; ++i)
data[i] = rhs[i];
return *this;
}
explicit VectorExpression(const V *ref = 0)
: VectorExpressionBase<T,N,V>(ref) {}
// Can define all kinds of operators and functions here such as
// +=, *=, unary + and -, max(), min(), sin(), cos(), ...
// They would automatically apply to MyVector objects and to the
// results of other operators and functions
};
template<class T, int N>
class MyVector : public VectorExpression<T,N,void> {
};
template<class T, int N, class VA, class VB>
class VectorSum {
VectorExpression<T,N,VA> &a;
VectorExpression<T,N,VB> &b;
public:
VectorSum(VectorExpression<T,N,VA> &aa, VectorExpression<T,N,VB> &bb)
: a(aa), b(bb) {}
T operator[] (int i) const { return a[i] + b[i]; }
};
template<class T, int N, class VA, class VB>
VectorExpression<T,N,VectorSum<T,N,VA,VB> >
operator+(const VectorExpression<T,N,VA> &a,
const VectorExpression<T,N,VB> &b)
{
VectorSum<T,N,VA,VB> sum(a, b);
return VectorExpression<T,N,VectorSum<T,N,VA,VB> >(sum);
}
Class VectorExpression now just wraps the class that does the work (in this case VectorSum). This allows defining all kinds of functions and operators for VectorExpression only, rather than having to overload them for VectorSum, VectorProduct, etc.
MyVector derives from a special case of VectorExpression which has a specialized base class; this isn't really necessary but it's nice because it makes all functions and operators defined for VectorExpression also available for MyVector. By using a simple base class VectorExpressionBase that only deals with storage and the [] operator, all other operators and methods don't need to be duplicated in the specialization for V = void.
Users would only need to know about classes MyVector<T,N> (for storing data) and possibly about VectorExpression<T,N,V> if they want to define additional functions and operators. VectorExpressionBase and the classes like VectorSum don't need to be visible to the outside world.
I find my original solution somewhat cleaner conceptually because the meaning of each class is more clear and because it doesn't require the template parameter V, but this one is more efficient because it doesn't require any virtual functions, which can probably make a large difference in certain cases.
Thanks for pointing me to the right links!
P.S. Surely most / all of this isn't new but I thought it would be nice to summarize and explain it a bit. I hope it can help others.
EDIT
I changed the type of data member VectorExpressionBase<T,N,V>::ref from V& to V. This is needed since the temporary V object the reference was pointing at may no longer exist at the time the VectorExpression is evaluated. For example, the temporary VectorSum object stops existing when the operator+ function returns, making the returned VectorExpression object useless.
I also completed the code with some constructors and corrected the operator+ function.

Is there a way to forward all assignment operators (+=, *=, etc.) to implicitly use an overridden direct assignment operator (=)?

I know "forwarding" is an unrelated concept in C++11 (as in "perfect forwarding") but it's the first word that comes to mind for me for describing the problem.
I'm overriding the operator= in a wrapper class Proxy,
template<typename T>
class Proxy
{
public:
enum class State
{
NEVER_SET = 0,
SET
};
operator const T& () const
{
if ( _state != State::SET )
{
throw std::domain_error{ "using unset data" };
}
return _data;
}
Proxy<T>& operator=(const T& val)
{
_data = val;
_state = State::SET;
return (*this);
}
private:
T _data;
State _state = State::NEVER_SET;
};
but find myself also needing to add:
Proxy<T>& operator+=(const T& val)
{
_data = (*this) + val;
_state = State::SET;
return (*this);
}
Proxy<T>& operator-=(const T& val)
{
_data = (*this) - val;
_state = State::SET;
return (*this);
}
Proxy<T>& operator*=(const T& val)
{
_data = (*this) * val;
_state = State::SET;
return (*this);
}
Proxy<T>& operator/=(const T& val)
{
_data = (*this) / val;
_state = State::SET;
return (*this);
}
// ...and so on.
Is there a trick to "forwarding" all assignment operators (+=, -=, *=, /=, %=, >>=, <<=, |=, &=, ^=) so that I don't have to define them? That is, a way to make
Proxy<double> x = 7;
Proxy<double> y = 43;
x += y;
automatically "unravel" to
Proxy<double> x = 7;
Proxy<double> y = 43;
x = x + y; // cast operator converts x and y to double, then direct assigns sum,
// therefore no += needing definition in Proxy<T>
You can use the CRTP, but if you aim to only have an explicit = in your Proxy class, you'll need to provide some access to types for which the other operators are already available. Put another way, you can't say a1 = a2 + a3 if you've defined how to assign but not how to add. I address this below by expecting a get() function that exposes some state that can be operated on. It's far more typical (and probably practical) to explicitly define e.g. += then have + defined in terms of it....
#include <iostream>
template <typename T>
struct Implied_Ops
{
T operator+(const T& rhs) const
{
return rhs.get() + static_cast<const T*>(this)->get();
}
T& operator+=(const T& rhs)
{
return static_cast<T&>(*this) = operator+(rhs);
}
};
struct X : Implied_Ops<X>
{
X(int n) : n_(n) { }
X& operator=(const X& rhs) { n_ = rhs.n_; return *this; }
int get() const { return n_; }
int n_;
};
int main()
{
X x { 10 };
X x2 = x + x;
X x3 = x + x2;
std::cout << x.n_ << ' ' << x2.n_ << ' ' << x3.n_ << '\n';
}
Another approach that shouldn't be overlooked is macros....
Yes with CRTP.
template<class D>
struct plus_equals {
template<class Rhs>
D& operator+=(Rhs&& rhs){
D*self=static_cast<D*>(this);
self->_data = (*self)+std::forward<Rhs>(rhs);
self->_state= State::SET;
return *self;
}
};
then inherit your class Foo publically from plus_equals<Foo>.
Of course you need to write that boilerplate for each operator, so it does not help much for one type.

Overloading operator= for structs, within classes

We have the following:
(pseudoish)
class MyClass
{
private:
struct MyStruct{
MyStruct operator=(const MyOtherStruct& rhs);
int am1;
int am2;
};
};
We'd like to overload the = operator in the MyClass.cpp to do something like:
MyStruct&
MyStruct::operator=(const MyOtherStruct& rhs)
{
am1 = rhs.am1;
am2 = rhs.am2;
}
However, it doesn't want to compile. We're getting an error similar to
"missing ; before &"
and
"MyStruct must be a class or namespace if followed by ::"
Is there some concept here I'm missing?
You need to move your operator= for MyStruct into the struct declaration body:
class MyClass
{
private:
struct MyStruct{
int am1;
int am2;
MyStruct& operator=(const MyOtherStruct& rhs)
{
am1 = rhs.am1;
am2 = rhs.am2;
return *this;
}
};
};
Or if that's not possible because MyOtherStruct is incomplete or don't want to clutter the class declaration:
class MyClass
{
private:
struct MyStruct{
int am1;
int am2;
MyStruct& operator=(const MyOtherStruct& rhs);
};
};
inline MyClass::MyStruct& MyClass::MyStruct::operator=(const MyOtherStruct& rhs)
{
am1 = rhs.am1;
am2 = rhs.am2;
return *this;
}
The syntax is
MyStruct& operator=(const MyOtherStruct& rhs) {
// assignment logic goes here
return *this;
}
for an operator directly within the body of MyStruct. Also note that I added the idiomatic return *this to let the assignment return a reference to this object.
EDIT in response to OP editing the question.
You can also declare the operator in the body, and define it somewhere else. In this case, the syntax is:
MyClass::MyStruct& MyClass::MyStruct::operator=(const MyOtherStruct& rhs) {
// assignment logic goes here
return *this;
}