Reputation: 3200
Suppose we have 2 classes:
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 &);
//...
};
and we want Array::operator=
and Array
's freind operator+
to do the same thing as DataStructure::operator=
and DataStructure
's freind operator+
, except they should return Array &
,const Array &
instead of DataStructure &
,const DataStructure &
. I need to do it with dozens of methods, so is there a simpler way to implement it than the following?
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);
}
EDIT: I came up with another idea, although it's a pretty bad one:
class Array;
class DataStructure {
public:
//...
operator Array &() const;
};
//...
DataStructure::operator Array &() const {
return (Array &)*this;
}
This way DataStructure
is implicitly converted to an Array
whenever needed, although it still can't handle correctly cases where both DataStructure
and Array
are legal but do different things, as in this example:
//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;
}
Thanks you!
Upvotes: 1
Views: 183
Reputation: 3200
Eventually I managed to find an answer. For operator=
:
class Array : public DataStructure {
public:
//...
using DataStructure::operator=;
Array &operator=(const DataStructure &);
};
Writing only Array &operator=(const DataStructure &);
would hide DataStructure::operator=
, but with the using
statement it only changes the method's return type.
Note: the using
statement must precede the line Array &operator=(const DataStructure &);
, otherwise operator=
would be ambiguous.
As for operator+
, the only solution I found is very problematic. It uses templates:
public DataStructure {
public:
template<class T> friend const T &operator+(int, const T &);
};
For instance, if the original implementation was
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;
}
and we want to achieve the same result as in
const Array &operator+(int x, const Array &other) {
return (const Array &)(x + (DataStructure)other);
}
than we can simply write:
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;
}
However, if there exists a function operator+(int,/*const*/ ThirdClass /*&*/)
that has nothing to do with DataStructure
or Array
than we would have to change it, which might mess up the code. Luckily there are usually just a few friend functions, so implementing a new method that performs a conversion (as shown in the question) isn't so bad.
Upvotes: 0
Reputation: 64203
Your implementation is not good : the operator=
should return reference to object of type Array, and should not be virtual :
Array &Array::operator=(const DataStructure &other) {
DataStructure::operator=(other);
return *this;
}
You can change DataStructure
to use 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);
}
Check live demo. Then you have to implement the method add
in your derived class Array.
To your edit :
Your new idea is an awful way of doing things in c++. What you do there is tell your compiler : "stop complaining, I know what I am doing". Also, it causing an undefined behaviour. It may appear to work, until you application starts crashing one day.
Upvotes: 1