I want to design a common interface which has a method that let me multiply two object which has this interface, returning a new object of the same class as the result. In order to keep it easy, I'm going to focus just on one class which implement this interface. The problem: My problem is the returned object. Let's see:
The goal before having an interface:
class C {
public:
int get() { return v; }
void set(int value) { v = value; }
C operator * (C &l) {
C r;
r.set(get() * l.get());
return r;
}
private:
int v;
};
In this case, the operator* method return an object of type C, but not a reference (keep this in mind). It takes advantage of the return value optimization. Now, let's arrive to the problem: In this case I want to design an interface:
struct I {
virtual int get() = 0;
virtual void set(int value) = 0;
virtual I& operator * (I &l) = 0;
};
In this case, I can't use a returned type I (by value) for the operator* method, because I is abstract. OK, let's go to the problem:
class C : public I {
public:
int get() { return v; }
void set(int value) { v = value; }
I& operator * (I &l) {
C r;
r.set(get() * l.get());
return r; // warning: reference to local variable ‘r’ returned
}
private:
int v;
};
The problem here is I'm returning a reference to a local variable.
How can I do this, in the ri开发者_如何学Pythonght way, without using dynamic allocation?
Thanks in advance.
You can't do this in such a polymorphic way without using dynamic allocation.
Are you sure that multiplication is really meaningful in a polymorphic way? If so, you'll have to return a dynamically allocated pointer and manage its lifetime (possibly with a smart pointer). But in this case it doesn't fit the normal semantics if operator*
so you should probably create a special function to do that work.
Also note that you have a few quirks that aren't C++-idiomatic. get
should be a const method, the parameter to your operator*
should be by const reference or value (no one wants operator*
to modify one of its operands as that violates the principle of least surprise). And typically operator*
returns its result by value to prevent confusions over who owns any allocated returned memory if the operator didn't return by value.
Either return a pointer to a dynamically allocated object (I*
) or return a C
by value.
Returning a reference is possible, but it's confusing, so don't do the following:
virtual I &operator*(I &l) {
C *r = new C();
r->set(get() * l.get());
return *r; // warning: reference to local variable ‘r’ returned
}
The problem here is that, although the return value looks like a value, it must still be delete
'd with the unusual syntax delete &r;
I believe you should be using operator*=
not operator*
in this case.
In the operator*=
you return a reference to *this
, which is not a local variable, so it's ok to return.
In the operator*
case, it should be const and you need to return by value (well, the language doesn't force you to, but if you're doing multiplication, it's very likely it's the most sensible thing to do). I'm not sure how to make such a thing work with virtual functions, I would generally use templates (though you loss run time polymorphism with such an approach).
Edit: What you want is possible ... however it's a really bad idea.
The requirement for no memory allocation is flatly impossible. Multiplication needs to create a new object (by definition), and a polymorphic object needs to be created on the heap (if you want to avoid slicing and refer to it by the interface).
However if you still want to write I* result = a*b*c
with polymorphic a,b,c
you can accomplish this by using a proxy object and use some implicit casting..
You can create a proxy object with some implicit casting thrown in:
struct Iref {
I* ref;
Iref(I* aref):ref(aref){};
operator I*() { return ref; }
Iref operator * (I& b);
Iref operator * (Iref b);
Iref operator * (I* b);
};
With this proxy and appropiately written methods you can end up with:
int main()
{
C a(1), b(2), c(3);
I* result = a*b*c;
return 0;
}
The remaining problem is the inherent memory leak. Either you use a garbage collector with your application. I have no experience with these, I just know it's possible. Or you let the proxy object handle memory deallocation.
This rather elaborate trickery should show how operator*
and polymorphism together are not a good idea. There are other problems, as with polymorphism you may end up with a * b
and b * a
having different results.
1 - You cannot return an object instance typed like 'I' (abstract type)
2 - If You want to return an object, not a pointer, You should use the normal return type ('C'). Other way: make 'I' not abstract and return 'I'.
3 - The recommended way: return just I* and don't forget to delete the object later.
精彩评论