我在程序
中有这样的语法/* The Object1 is allowed to be changed */
class Object1 : BaseClass {
BaseClass *link;
int i;
public:
Object1(int a){i=a;}
Object1(int a, Object1 /*place1*/ o) {i=a; link= &o;}
};
int main(){
/* The initialization syntax must be preserved. No any new(), no other local objects b,c */
Object1 a(1, /*place2*/ Object1(2));
...
}
我需要在place1中做什么?我想保存第一个对象中第二个对象的链接(指针)。我应该使用place1参考“&”吗?
什么类型的地方有“Object1(2)”?它是匿名对象的构造函数吗?它会有“自动”存储类型吗?
由于
更新:
在place2中,语法是固定的,我真的必须支持创建“链”,比如
Object1 a(1, Object1(2, Object1(6, Object1(999753))));
我不能在a。的定义中添加任何符号。
UPDATE2:
for place1:Object1(int a, Object1 &o) {i=a; link= &o;}
和Object1 a(1, Object1(2));
in place2我有编译错误(g ++):
main.cpp||In function `int main()':|
main.cpp|19|error: no matching function for call to `Object1::Object1(int, Object1)'|
main.cpp|9|note: candidates are: Object1::Object1(const Object1&)|
main.cpp|14|note: Object1::Object1(int, Object1&)|
main.cpp|13|note: Object1::Object1(int)|
答案 0 :(得分:4)
在“place1”中,您需要一个参考。 Object1
未完全定义,因此您无法按值获取它。那就是说,你不想通过价值;当你获取它的地址时,你将获得副本的地址,而不是实际的对象。
由于您只需要指向BaseClass
的指针,因此仅对该参数设置该限制可能更有意义。 (当然,如果您确实需要Object1
,请在link
:Object1* link;
类型中反映出来。
还要考虑使用初始化列表:
Object1(int a) : i(a), link(0) /* <- important! */ { }
Object1(int a, BaseClass& o) : i(a), link(&o) { }
始终使用初始化列表。
“place2”使用构造函数创建一个未命名的Object1
实例。它有无存储(?) auto
存储空间和dies at the end of the expression。
也就是说,一旦你在Object1 a(1, /*place2*/ Object1(2));
中击中了分号,它就不再存在了,你有一个指向不存在的对象的指针!这会导致未定义的行为。
给它一个超出表达式的生命周期:
Object1 x(2);
Object1 a(1, x);
始终确保在引用某个对象时,它会在您引用它的整个时间内生效。
您的新编译错误是因为您无法引用临时变量。但可以使用const-reference。问题是,你的指针现在需要指向const BaseClass
,这可能会削弱你想要的东西。
不幸的是,您的设计需要重新加工。
答案 1 :(得分:2)
放置1:在此处使用指针(*)代替引用(&amp;)。指针语法更明确地表示链接。
地点2:这里将创建所谓的“临时”对象。是的,它将涉及对Object1的构造函数的调用。此外,是的,存储将是“自动”,因为它将在堆栈上创建。
但是,要小心。临时将在您在构造函数中引用它之前死掉。这肯定会使你的程序崩溃。如果必须传递临时值,则可以通过在堆上创建副本来成功。像这样:
class Object1
{
BaseClass* link;
int i;
Object1(int a) : i(a), link(NULL) {}
Object1(int a, const Object1& o) : i(a), link(new new Object1(o)) {}
Object1(const Object1& other) i(other.i) link(other.link) {} //Copy constructor
virtual ~Object1() { delete link; } //Don't forget the 'delete' in destructor.
};
然后在你的主要你可以()这样做:
int main()
{
Object1 a(3, Object1(2));
....
}
请注意Object1类中的析构函数。确保在其中的链接上调用delete operator。然而,这样的呼叫会导致所有孩子被删除。如果这不是您想要的,请相应地更改删除机制。无论如何,别忘了删除。
另外,确保析构函数是虚拟的。那是因为你将在指向派生类对象的基类指针上调用delete。
答案 2 :(得分:0)
您不能在声明中使用Object1
的实例(它尚未声明)。您可以在类声明之前添加一个称为前向声明的内容,如下所示:
// Forward declaration
class Object1;
// Now the class body
class Object1 {
// some reference to Object1 here
};
但是,我仍然不完全清楚你要对这段代码做什么。有关您希望此构造函数执行的操作的更多信息可能会有所帮助?我怀疑你可能想要使用指针或传递引用,而不是传值。
答案 3 :(得分:0)
构造函数参数o
是您传入的Object1
实例的副本(因为它是按值传递 。在您的构造函数中,当您将成员指针设置为其地址时,该地址就是堆栈帧,在构造函数返回后它将无效。
这是另一种方法(当然还有其他方法):
class Object1 : BaseClass
{
BaseClass *link;
int i;
public:
// - Prefer initialization to assignment
// - Initialize ALL of your members
Object1(int a) : link(NULL), i(a) {}
// This instance assumes ownership of p
Object1(int a, Object1 *p) : link(p), i(a) {}
~Object1() { delete link; }
};
int main()
{
Object1 a(1, new Object1(2));
...
}
编辑:嗯,我能看到你使用链式设计的唯一方法就是这样的丑陋:
class Object1 : BaseClass
{
BaseClass *link;
int i;
public:
Object1(int a) : link(NULL), i(a) {}
Object1(int a, const Object1& o) : link(new Object1(o)), i(a) {}
// Copy constructor
Object1(const Object1& other) : link(NULL), i(other.a)
{
// Deep copy linked object
if (other.link != NULL)
{
link = new Object1(*other.link);
}
}
// Assignment operator that does deep copy
const Object1& operator=(const Object1& that)
{
// Check for assignment to self
if (this != &that)
{
delete this.link;
this.link = NULL;
// Deep copy linked object
if (that.link != NULL)
{
this.link = new Object1(*that.link);
}
this.i = that.i;
}
}
~Object1() { delete link; }
};
int main()
{
Object1 a(1, new Object1(2));
...
}
答案 4 :(得分:0)
你写的不可能做你想做的事。 Object1
/*place2*/
的生命周期在构造函数之后结束,因此您将拥有一个悬空指针。
一般情况下,您希望Object1
/*place2*/
成为引用或直接指针[在这种情况下,您不会获取地址,只需直接复制它]。
但是,你必须非常小心你存储的指针的生命周期,正如初始点所证明的那样。
答案 5 :(得分:0)
您要实现的是堆栈上的动态数组。您想要创建一个对象列表,并且不在堆中保留它们。 C ++不支持这一点,至少不在一个函数的范围内。
您可以使用递归重构代码并保持链接列表在堆栈中上升,但这不会是C ++ -ish。
否则,唯一的解决方案是使用堆(std::list
,std::auto_ptr
或std::unique_ptr
应该这样做),正如其他人所建议的那样。