C++ getter 方法的最佳实践是什么,该方法应该返回一个非平凡类型,而是一个类或结构类型的成员。
MyType MyClass::getMyType() { return mMyType; }
const MyType& MyClass::getMyType() { return mMyType; }
MyType* MyClass::getMyType() { return &mMyType; }
哪里
class MyType { /* ... */ };
class MyClass
{
private:
MyType mMyType;
}
我特别担心这个方法的以下用法。您能否详细说明这可能如何影响复制对象,以及如果
function()
想要保存它以供进一步使用,则悬空引用和野生指针的危险。
MyType* savedPointer;
SomeType function(MyType* pointer) { savedPointer = pointer; };
a.适用于 1. 和 2.
{
MyType t = myClass.getMyType();
function(&t);
}
// is savedPointer still valid here?
b.适用于 1. 和 2.
{
const MyType& t = myClass.getMyType();
function(&t);
}
// is savedPointer still valid here?
c.适用于 1. 和 2.
{
MyType& t = myClass.getMyType();
function(&t);
}
// is savedPointer still valid here?
d。有效期为 3 次。
{
MyType* t = myClass.getMyType();
function(t);
}
// is savedPointer still valid here?
其中
myClass
是 MyClass
类型的对象。
您可以提供 const 和非 const 版本:
MyType & MyClass::getMyType() { return mMyType; }
MyType const & MyClass::getMyType() const { return mMyType; }
我不会提供指针版本,因为这意味着返回值可能是空指针,而在本例中永远不可能是空指针。
然而,真正的要点是,您基本上是在让调用者直接访问内部对象。如果这是您的意图,那么您不妨将数据成员公开。如果不是,那么您将需要更加努力地隐藏该对象。
一种选择是保留
MyType const &
访问器,但提供更间接的方法来修改内部对象(setMyType(…)
或更适合您试图在包含类级别表达的语义的东西)。
一般来说,您应该更喜欢按值返回,除非您 明确想要保证引用将指定 一个成员(它公开了您的实现的一部分,但是 在类似
std::vector<>::operator[]
的情况下是理想的)。返回
引用可以防止以后对类进行更改,因为这意味着
您无法返回计算值。 (这尤其是
如果该类被设计为基类,则很重要,因为
返回引用会为所有派生创建此限制
课程。)
唯一应该通过指针返回的时间是查找或 涉及到一些事情,可能会导致必须返回 空指针。
返回对 const 的引用可能是一个有效的优化,如果 探查器指示此处的性能问题,并且调用 站点还可以处理 const 引用(不修改 返回值,对象的生命周期没有问题)。它 必须权衡额外的限制 当然要实施,但在某些情况下,这是合理的。
我总是返回一个常量引用。如果您需要修改它返回的值,只需使用 setter 函数。
应避免按值返回,例如:
MyType MyClass::getMyType() { return mMyType; }
,因为您将复制对象的内容。我看不到您可以获得的收益,但我看到了性能方面的缺点。
通过 const 引用返回:
const MyType& MyClass::getMyType() { return mMyType; }
更常用这种方式:
const MyType& MyClass::getMyType() const { return mMyType; }
MyType& MyClass::getMyType() { return mMyType; }
始终提供 const 版本。非常量版本是可选的,因为它意味着有人可以修改您的数据。这是我鼓励您使用的。
按地址返回:
MyType* MyClass::getMyType() { return &mMyType; }
主要用于数据可选存在的情况。使用前经常需要检查。
现在,对于您的用例,我强烈建议不要将指针保存为超过一个范围。我经常会导致所有权问题。如果你必须这样做,请查看 shared_ptr。
对于您的示例,有两种情况:
a.在右大括号之后,savedPointer 将不再有效。
b、c 和 d。 savePointer 在右大括号之后有效,但要注意它不应该比其寿命长
myClass
。
a)
MyType t =
将为 1 和 2 创建对象的副本。一旦 t 超出范围,保存的指针将无效。
b) 保存的指针对于返回引用的情况有效,但对于返回对象的情况无效。作为参考,指针的生命周期与 myClass 相同。当然,const ref 上的 &t 是 const t* 而不是 t*,因此无法在对
function(MyType*)
的调用中进行强制转换。
c) 与 b 相同,但代码对于 2 无效,因为您无法将
const MyType&
转换为 MyType&
。一般来说,这是不好的做法,const 形式更容易被接受。
d)savedPointer 将与 myClass 具有相同的生命周期。
我通常倾向于返回引用或 const 引用,具体取决于您期望能够对返回值执行什么操作。如果您返回一个引用(非常量),您可以执行以下操作:
myClass.getMyType() = ...
,而如果您返回一个常量引用,则该对象是只读的。