C++ 引用成员变量作为类成员

C++ 引用成员变量作为类成员,c++,reference,C++,Reference,在我的工作场所,我看到这种风格被广泛使用:- #include <iostream> using namespace std; class A { public: A(int& thing) : m_thing(thing) {} void printit() { cout << m_thing << endl; } protected: const int& m_thing; //usually would be mo

在我的工作场所,我看到这种风格被广泛使用:-

#include <iostream>

using namespace std;

class A
{
public:
   A(int& thing) : m_thing(thing) {}
   void printit() { cout << m_thing << endl; }

protected:
   const int& m_thing; //usually would be more complex object
};


int main(int argc, char* argv[])
{
   int myint = 5;
   A myA(myint);
   myA.printit();
   return 0;
}
#包括
使用名称空间std;
甲级
{
公众:
A(int&thing):m_thing(thing){}

void printit(){Cuth

成员引用通常被认为是坏的,它们比成员指针更难生存。但是它不是特别不符合标准,也不是特别命名的习惯用法或事物。它只是混淆。< /P> < P> C++提供了一个管理对象生命周期的好机制,尽管类/结构构造。这是C++的最佳特性之一。超过其他语言

当您通过ref或pointer公开成员变量时,原则上违反了封装。此习惯用法允许类的使用者在不使用它的情况下更改A的对象的状态(A)拥有对它的任何知识或控制权。它还使使用者能够在a对象的生命周期之外保留指向a内部状态的引用/指针。这是一种糟糕的设计。相反,可以重构类以保留指向共享对象的引用/指针(而不是拥有它),并且可以使用构造函数设置这些引用/指针(强制使用生命周期规则)。共享对象的类可设计为支持多线程/并发(视情况而定)

有没有一个名字来形容这个成语?

这种用法没有名称,只是称为“类成员引用”

我假设这是为了防止复制大型复杂对象可能带来的巨大开销?

是的,还有希望将一个对象的生存期与另一个对象关联的场景

这通常是一种好的做法吗?这种方法是否存在缺陷?

取决于您的使用情况。使用任何语言功能就像“为课程选马”。需要注意的是,每个(几乎所有)语言功能都存在,因为它在某些情况下很有用。
在将引用用作类成员时,需要注意以下几点:

  • 您需要确保引用的对象在类对象存在之前一直存在
  • 您需要初始化构造函数成员初始值设定项列表中的成员。您不能有一个延迟初始化,这在指针成员的情况下是可能的
  • 编译器不会生成复制赋值
    操作符=()
    ,您必须自己提供一个。在这种情况下,确定
    =
    操作符应采取的操作是很麻烦的。因此,基本上您的类变成了不可赋值的
  • 引用不能为
    NULL
    ,也不能用于引用任何其他对象。如果需要重新放置,则不能像指针那样使用引用
对于大多数实际目的(除非您真的担心由于成员大小而导致的高内存使用率),只要有一个成员实例,而不是指针或引用成员就足够了。这就省去了您对引用/指针成员带来的其他问题的大量担忧,但会牺牲额外的内存使用

如果必须使用指针,请确保使用智能指针而不是原始指针。这将使使用指针的生活更加轻松

有没有一个名字来形容这个成语

在UML中,P>称为聚合。它与组成不同,因为成员对象不是引用类所拥有的。在C++中,可以通过引用或指针来实现两种不同的聚合。 我假设这是为了防止复制大型复杂对象可能带来的巨大开销


不,这将是一个非常糟糕的理由。聚合的主要原因是包含的对象不属于包含的对象,因此它们的生存期不受约束。特别是引用的对象生存期必须比引用的对象的生存期长。它可能创建得更早,并且可能超过li的结束时间容器的时间。除此之外,被引用对象的状态不受类控制,但可以在外部更改。如果引用不是
const
,则类可以更改位于其外部的对象的状态

这通常是一种好的做法吗?这种方法是否存在缺陷

它是一种设计工具。在某些情况下,这是一个好主意,但在某些情况下,它不会。最常见的陷阱是,持有引用的对象的生存期决不能超过被引用对象的生存期。如果封闭对象在被引用对象被销毁后使用引用,则会有未定义的行为。通常最好选择组合而不是聚合,但如果您需要它,它和其他工具一样好。

它被称为:class
a
将依赖项作为其构造函数的参数,并将对依赖类的引用保存为私有变量

电视上有一个有趣的介绍

对于常量正确性,我要写:

using T = int;

class A
{
public:
  A(const T &thing) : m_thing(thing) {}
  // ...

private:
   const T &m_thing;
};
但该类的一个问题是它接受对临时对象的引用:

T t;
A a1{t};    // this is ok, but...

A a2{T()};  // ... this is BAD.
最好添加(至少需要C++11):


无论如何,如果更改构造函数:

class A
{
public:
  A(const T *thing) : m_thing(*thing) { assert(thing); }
  // ...

private:
   const T &m_thing;
};
这几乎可以保证

此外,由于构造函数使用指针,因此
a
的用户更清楚地知道,他们需要注意所传递对象的生命周期。


有些相关的主题是:


一个可能的陷阱是,如果您在成员变量中引用的对象在其他地方被破坏,并且您试图通过类访问它,那么您提供的支持引用通常被认为是不好的吗?“不,这将是一个非常不好的理由使用它”.你能详细说明一下这一点吗?可以用什么来代替呢?@coincoin:具体实现什么?
来防止pos
class A
{
public:
  A(const T *thing) : m_thing(*thing) { assert(thing); }
  // ...

private:
   const T &m_thing;
};