【问题标题】:Constant Reference Wrapper常量引用包装器
【发布时间】:2011-11-13 01:32:02
【问题描述】:

我在 Mark Allen Weiss 的数据结构一书中看到了以下代码。

template <class Object>
class Cref
{
public:
Cref ( ) : obj ( NULL ) { }
explicit Cref( const Object & x ) : obj ( &x ) {
const Object & get( ) const
{
if ( isNull( ) )
  throw NullPointerException( ) ;
else
 return *obj;
}
bool isNull( ) const
( return obj == NULL; }

private:
const Object *obj;
};

所以这里的重点是分配 null/初始化一个常量引用。但我不确定我是否理解以下内容: 1. 我们用另一个常量引用 x 初始化一个常量引用。但是为什么它再次作为 obj(&x) 完成? const Object & x 中的 & 与 obj(&x) 中的 &x 不同?我看到了这一点,但不是很清楚为什么会这样。请解释一下。 2. get 方法() - 我们尝试返回这个类的私有成员 obj 的 const 引用。它已经是一个常量引用。为什么返回 *obj 而不仅仅是 obj ? 3. 为什么要显式关键字?如果发生隐式类型转换会发生什么?有人可以为此提供一个场景吗?

谢谢

【问题讨论】:

    标签: c++ pointers constructor constants


    【解决方案1】:
    1. 成员obj 的类型是Object*,但构造函数需要一个引用。因此,要获得指针,必须应用地址运算符&amp;。并且成员是指针,因为它可以为 NULL(在默认构造函数中设置),并且引用永远不能为 NULL。

    2. 私有成员不是 const 引用,而是poinetr 到const。它被取消引用以获得引用。

    3. 在这种特定情况下,我也看不到潜在的隐式转换有任何负面影响。

    【讨论】:

    • 感谢您的澄清!特别是#2! :)
    • 也是关于#1,这意味着这是声明的问题。因为我们只能声明一个像 const Object & x; 这样的 const 引用。当实际将其分配给指针时, ptr = &x 是不可避免的。我的理由对吗?
    • @SuprajaJayakumar:从逻辑的角度来看,引用基本上命名了一个对象。也就是说,在构造函数内部,传递给它的对象具有名称x(并且是 const,因为它是一个 const 引用)。因此,您使用 x 与使用该类型的变量完全一样。要获得指向变量的指针,请使用 addess-of 运算符 &amp;,因此您对 x 执行相同操作。引用也使用符号&amp; 定义的事实在逻辑上与此无关。如果他们决定为此使用关键字ref,情况也是如此。
    【解决方案2】:

    1) obj(&amp;x) 中的&amp;x 用作地址运算符。

    2) 不,它是一个指针。它的时间是Object *,而不是Object &amp;。

    3) 防止从可能有自己的类型转换运算符的不兼容指针类型进行转换。

    C++ 提供三种可用的 null:

    • NULL - 已过时;仅用于检查返回指针的 C 函数的返回值
    • 0 - 已弃用;文字零在标准中定义为空指针
    • nullptr - 从 C++11 开始,这是测试 null 的首选方法。此外,nullptr_t 是一个类型安全的 null。

    【讨论】:

      【解决方案3】:

      1) 令牌&amp;具有三种含义:

      • 一元地址运算符:获取任何左值表达式的地址,并给出指向该对象的指针。
      • 引用标记:在声明中,表示引用类型。
      • 二进制位与运算符 - 此处未使用

      因此,了解您查看的是声明还是表达式非常重要。

      explicit Cref( const Object & x )
      

      这里的印记出现在函数参数的声明中,这意味着参数x 的类型是对Object 的引用,即const。

      : obj ( &x ) {}
      

      这里的操作符用于成员初始化表达式。成员obj 被初始化为指向x 的指针。

      2) 由于成员obj实际上是一个指针,所以需要解引用运算符一元*来获取引用。

      3) 一般来说,在任何可以只接受一个参数的(非复制)构造函数上使用explicit 是个好主意。不幸的是,该语言并没有默认为显式,而是让您在需要时使用某种“隐式”关键字。在这种情况下,如果构造函数是隐式的,可能会发生一件相当糟糕的事情:

      Object create_obj();
      void setup_ref(Cref& ref) {
          ref = create_obj();
      }
      

      没有编译器错误或警告,但 setup_ref 函数存储了一个指向临时对象的指针,该指针在函数返回时无效!

      【讨论】:

        【解决方案4】:

        1) obj 的类型不是引用,obj 是指针,而 const 指针必须用地址初始化,因此必须应用地址运算符 &。 2)get()方法返回的引用不是对类成员obj的引用,而是对obj指向的对象的引用,所以必须使用*来尊重它。 3) 关键字explicit表示我们拒绝隐式转换,也就是告诉编译器不要用这个构造函数为我们做隐式转换。
        示例:

        class Cref<Object> A;
        Object B;
        A=B;

        没有显式也可以——因为我们需要在右侧有一个 Cref 对象,编译器将自动使用构造函数 Cref( const Object & B ) 生成一个 Cref 对象。但是如果添加显式,编译器不会进行转换,会出现编译错误。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-07-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多