为什么在C ++中,对象A,B
//interface, case #1
class A {
B bb;
}
A::A()
{ //constructor
bb = B();
}
//interface, case #2
class A {
B *bb;
}
A::A()
{ //constructor
bb = new B();
}
为什么案例#2有效但不是#1 ??
编辑:我现在知道了。但对于案例#1,如果A的实例被释放,它的bb是否也会自动释放?情况#2你必须明确地调用bb = NULL吗?
答案 0 :(得分:4)
两者都有语法错误,因此“不起作用”并不是特定于一个或另一个。您还没有声明A::A
构造函数,因此在尝试定义时会出现语义错误。
如果在A类声明之前B的完整声明可用,那么它将编译:
class B {};
//interface
class A {
A();
B bb;
};
A::A()
{ //constructor
bb = B();
}
在bb=B()
行中,bb已经被构造,因为它是A的成员。然后你构造另一个B,然后将B的值复制到bb。这有点浪费。如果要将参数传递给bb的构造函数,请使用初始化器。
另一方面,如果你不想在A的定义之前放置B的定义,并且只有前向引用它,那么编译器就无法确定B对象有多大。 。它需要知道B有多大来确定A中允许bb的空间大小。所以它不能在没有B的情况下编译A.
在你的第二种情况下,你改为使用指向B的指针。无论指向什么,指针都是相同的大小。这样编译器可以计算出A的大小,并且在实际使用B之前只需要B的完整声明,例如通过在new B()
表达式中调用B的构造函数。
答案 1 :(得分:2)
在C ++中,如果声明一个对象,则不需要初始化它。声明时调用构造函数。
答案 2 :(得分:2)
因为在编译时,创建B对象所需的内存量是未知的。因此,有必要使用指向对象的指针,以便动态分配内存(当您调用new时)。
答案 3 :(得分:1)
显示的代码太不完整了。除非你展示B的定义,否则我恐怕没人能回答。我的猜测是B类是不可复制的(例如私人运营商=)。使用可复制的B类,您提供的示例应该可以使用。
答案 4 :(得分:1)
看起来你的“B”类隐藏了operator =。否则,你写的东西应该编译。
但是,没有必要。这应该有效:
A::A() : bb()
{ //constructor
}
但是,由于您正在调用默认构造函数,因此无需显式声明它。这可能很容易:
A::A() // bb is automatically constructed, since it's a member variable and not a pointer.
{
}
答案 5 :(得分:1)
如果B类的定义(不是声明)出现在A类声明之前,那么你的情况#1应该编译好。
正如Oxley指出的那样,原因是C ++需要知道B对象需要多少内存,如果没有B的定义就不能这样做。
但是,如果使用指针(如#2的情况),则所需的内存量是已知的,因为所有指针占用的内存量相同(32位或64位,具体取决于系统)。
因此,对于案例#2,你需要的只是在A定义之前的B的声明。(注意:声明,不是定义!当然,定义也不会受到伤害,但不一定需要)
只是为了确保我不会混淆任何人,(嘿,也许我没有C ++术语了)
声明:声明类或函数的存在,但不说它是什么。
e.g。
class A; //forward declaration
class C
{
A * a;
// .....
};
定义:实际定义类或函数。虽然对于一个类,它不一定完全定义它,但它定义了它的所有成员。
class A
{
int a;
int b;
void some_method(); //not defined here, only declared, but it's ok
};
答案 6 :(得分:0)
我认为案例A必须有效,因为如果没有人定义,编译器会提供复制构造函数。
答案 7 :(得分:-1)
问题对我来说是如何制作
A::A()
{ //constructor
bb = new B();
}
但没有新的。我想问题中的代码不是真正的代码。为什么'新'有效,但简单的任务没有。
我的回答正在关注。如果我以错误的方式理解问题或答案本身是错误的 - 请告诉我。
更改
A::A()
{ //constructor
bb = B();
}
到
A::A():
bb()
{
// some logic
}
并且在“new”的情况下具有一致性,最好像
那样实现A::A():
bb( new B() )
{
// some logic
}
在这两种情况下,当“某些逻辑”将开始执行时,您可以确定将抛出对象bb初始化或异常。
为了使您的案例可编辑,B应该已经实现了assign operator。
要编辑:您对案例1的猜测是正确的。在第2种情况下,你必须在类析构函数中调用delete bb。
请留下“-1”原因的消息。我真的很困惑。