我想设计一个通用接口,它有一个方法可以让我将两个具有此接口的对象相乘,并返回与结果相同的类的新对象。为了保持简单,我将专注于实现此接口的一个类。 问题:我的问题是返回的对象。 我们来看看:
拥有界面之前的目标:
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;
};
在这种情况下,operator *方法返回一个C类型的对象,但不是引用(请记住这一点)。它利用了返回值优化。 现在,让我们来解决问题: 在这种情况下,我想设计一个界面:
struct I {
virtual int get() = 0;
virtual void set(int value) = 0;
virtual I& operator * (I &l) = 0;
};
在这种情况下,我不能使用返回的类型I(按值)作为operator *方法,因为我是抽象的。好的,我们来看看问题:
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;
};
这里的问题是我正在返回对局部变量的引用。
如何在不使用动态分配的情况下以正确的方式执行此操作?
提前致谢。
答案 0 :(得分:2)
返回指向动态分配对象(I*
)的指针或按值返回C
。
可以返回引用,但这很令人困惑,所以不要执行以下操作:
virtual I &operator*(I &l) {
C *r = new C();
r->set(get() * l.get());
return *r; // warning: reference to local variable ‘r’ returned
}
这里的问题是,虽然返回值看起来像一个值,但它仍然必须是delete
'd,并带有异常语法delete &r;
答案 1 :(得分:2)
如果不使用动态分配,就不能以这种多态方式执行此操作。
你确定乘法在多态方式中真的有意义吗?如果是这样,您将必须返回动态分配的指针并管理其生命周期(可能使用智能指针)。但是在这种情况下,如果operator*
它不符合正常的语义,那么你应该创建一个特殊的函数来完成这项工作。
另请注意,您有一些不是C ++的怪癖 - 惯用语。 get
应该是一个const方法,operator*
的参数应该是const引用或值(没有人希望operator*
修改其操作数之一,因为它违反了最少的意外原则)。通常operator*
按值返回其结果,以防止在操作符未按值返回时,对拥有任何已分配的返回内存的人造成混淆。
答案 2 :(得分:1)
我认为在这种情况下你应该使用operator*=
而不是operator*
。
在operator*=
中,您返回对*this
的引用,该引用不是本地变量,因此可以返回。
在operator*
的情况下,它应该是const,你需要按值返回(好吧,语言不会强迫你,但是如果你正在进行乘法运算,那么它很可能是最明智的要做的事)。我不确定如何使用虚函数来处理这样的事情,我通常会使用模板(尽管使用这种方法会丢失运行时多态性。)
答案 3 :(得分:0)
编辑:您想要的是什么......但这是一个非常糟糕的主意。
无内存分配的要求完全不可能。乘法需要创建一个新对象(根据定义),并且需要在堆上创建多态对象(如果您想避免切片并通过接口引用它)。
但是,如果您仍想使用多态I* result = a*b*c
编写a,b,c
,则可以使用代理对象并使用一些隐式转换来实现此目的。
您可以创建一个代理对象,其中包含一些隐式转换:
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);
};
使用此代理和适当编写的方法,您最终可以:
int main()
{
C a(1), b(2), c(3);
I* result = a*b*c;
return 0;
}
剩下的问题是固有的内存泄漏。您可以在应用程序中使用垃圾收集器。我对这些没有经验,我只知道它是可能的。或者让代理对象处理内存释放。
这个相当复杂的技巧应该表明operator*
和多态一起不是一个好主意。还有其他问题,因为多态性可能导致a * b
和b * a
结果不同。
答案 4 :(得分:0)
1 - 您无法返回类型为“I”(抽象类型)的对象实例
2 - 如果要返回对象而不是指针,则应使用正常返回类型('C')。其他方式:让'我'不抽象并返回'我'
3 - 推荐方式:只返回I *,不要忘记稍后删除该对象。