我有一个A类,它由对象B和C组成。如何编写A的构造函数来获取B和C对象?我应该通过值,(const)引用还是指针传递它们?我应该在哪里解除分配?
我想到了指针,因为那时我可以写:
A a(new B(1,2,3,4,5), new C('x','y','z'))
但我不知道这是不是一个好习惯。有什么建议吗?
答案 0 :(得分:7)
通常你传递const引用:
A a(B(1,2,3,4,5), C('x','y','z'))
这里不需要指针。
通常您存储值,除非复制效率太低。 然后,类定义为:
class A {
private:
B b;
C c;
public:
A(const B& b, const C& c): b(b), c(c) { }
};
答案 1 :(得分:4)
我应该通过值,(const)引用还是指针传递它们?
请注意,如果您的类具有B和C的内部实例,那么通过引用,值或const引用传递它们很可能涉及使用复制构造函数或赋值运算符。使用指针时没有必要。
A a(新B(1,2,3,4,5),新C('x','y','z'))
通常(即并非总是)这是一个坏主意,因为:
我应该在哪里解除分配?
最好的办法是确保编译器自动为您释放参数。 这意味着通过引用,const引用或值传递。或使用智能指针。
答案 2 :(得分:2)
您传递的内容取决于您的需求。
你需要一份你传递的东西的副本吗?然后通过const-reference传递。
struct A
{
A(const B& b, const C& c) : m_b(b), m_c(c) {}
private:
B m_b;
C m_c;
};
并按照以下方式构建:
A myA(B(1,2,3), C(4,5,6));
如果您希望A
对象引用其他B
和C
个对象(但不拥有它们),请使用指针(或可能引用)。
答案 3 :(得分:1)
编辑:此处给出的示例不尊重三巨头的规则(感谢@Philipp!)。如果使用下面给出的A的定义,代码将在A的副本构造上崩溃,或者在A的分配上崩溃。为了正确定义代码,应该为A明确定义赋值运算符和复制构造函数(或明确禁止 - 声明为私有且从未实现过)。 (结束编辑)
我应该按值传递它们吗? (const)引用,还是指针?
如果A 使用 B和C,则通过A中的引用或指针保存它们。要在引用和指针之间进行选择,请参阅如何分配B和C.
如果它们是在与A相同的范围内构造的局部堆栈对象,则通过const引用传递它们。
如果它们是A使用的动态分配对象,则使A 拥有它们:通过指针传递它们,并让A的析构函数删除它们。
如果它们是A的可选组件,通过指针传递它们(可以为空)。
如果A不负责删除它们,请通过* const
传递它们。
我应该在哪里解除分配?
通常在您不再需要它们的地方:)。
如果需要超出A的范围(如果它们是A使用的外部对象),则在A的范围完成时删除它们。
如果它们归A所有,则在析构函数中删除它们。如果指针应该更改,那么在A的生命周期内删除它们也是有意义的。
这是一个例子,其中B是注入A(由A拥有)的可替换组件,C是A拥有的可选组件(但也注入A)。
(“拥有”表示A负责删除这两个对象)
class B;
class C;
class A
{
B* b;
C* c;
public:
A(B* const bb, C* const cc = 0) // cc is optional
: b(bb), c(cc)
{
}
void resetB(B* const bb = 0)
{
delete b;
b = bb;
}
~A()
{
resetB();
delete c;
}
};
{
A a(new B, new C);
a.resetB(); // delete B
a.resetB(new B); // delete former B and set a new one
} // both members of A are deleted
但我不知道这是否好 练习与否。有什么建议吗?
这取决于你,但你可以像A a(B(1, 2, 4), C(1, 2, 3))
那样简单地写A a(new B(1, 2, 4), new C(1,2,3));
(在前一种情况下 - 没有新的那个 - A :: b和A :: c应该是引用或者类中的对象/值,A根本不应该删除它们。
问题不应该是如果你想用B和C的动态分配编写语句,但是如果你需要。动态分配很慢,如果您没有要求,则不应该这样做。