【问题标题】:overloaded const and non-const class methods returning references in C++ [closed]在 C++ 中返回引用的重载 const 和非 const 类方法 [关闭]
【发布时间】:2013-06-05 21:13:12
【问题描述】:

我在 C++ 中有一个数据结构类,它带有一个访问某个对象(可能很大)的访问器,并且我有使用这个访问器的 const 和非常量方法,所以我需要重载它。我正在寻找对下面代码的批评 - 也许有一种方法可以完成同样的事情并且更简洁?

按照我的理解,在下面的例子中,方法get()有两种方法可以在不复制访问器中的代码的情况下实现这一点。我不确定这两种方法中的任何一种是否存在严重问题,我想在这里获得一些指导

我喜欢方法 A,因为:

  • 只有一个 const_cast
  • get() 方法的 const 版本返回一个副本
  • 非常量方法直接获取非常量引用

我不喜欢方法 A,因为:

  • 非 const 方法 get() 仅通过合同为 const,(未经编译器检查)
  • 很难获得 const 引用,但并非不可能

我喜欢方法 B,因为:

  • 编译器检查 const 方法 get() 的 const 性
  • 返回对象的副本由用户控制

我不喜欢方法 B,因为:

  • 需要两个难以阅读的 const_casts

这是这两种情况的(最小)示例代码。

/**
 * summary:
 * Two classes with an overloaded method which is
 * guaranteed (by contract) not to change any
 * internal part of the class. However, there is a
 * version of this method that will return a non-const
 * reference to an internal object, allowing the user
 * to modify it. Don't worry about why I would ever
 * want to do this, though if you want a real-world
 * example, think about std::vector<>::front()
 *
 * The difference between A and B can be summarized
 * as follows. In both cases, the second method merely
 * calls the first, wrapped with the needed
 * const_cast's
 *
 * struct A {
 *     int& get();
 *     int  get() const;
 * };
 *
 * struct B {
 *     const int& get() const;
 *           int& get();
 * };
 *
 **/

struct A
{
    int _val;

    A() : _val(7) {};

    // non-const reference returned here
    // by a non-const method
    int& get()
    {
        // maybe lots of calculations that you do not
        // wish to be duplicated in the const version
        // of this method...
        return _val;
    }

    // const version of get() this time returning
    // a copy of the object returned
    int get() const
    {
        // CONST-CAST!!?? SURE.
        return const_cast<A*>(this)->get();
    }

    // example of const method calling the
    // overloaded get() method
    int deep_get() const
    {
        // gets a copy and makes
        // a copy when returned
        // probably optimized away by compiler
        return this->get();
    }
};

struct B
{
    int _val;

    B() : _val(7) {};

    // const reference returned here
    // by a const method
    const int& get() const
    {
        // maybe lots of calculations that you do not
        // wish to be duplicated in the non-const
        // version of this method...
        return _val;
    }

    // non-const version of get() this time returning
    // a copy of the object returned
    int& get()
    {
        // CONST-CAST!? TWO OF THEM!!?? WHY NOT...
        return const_cast<int&>(const_cast<const B*>(this)->get());
    }

    // example of const method calling the
    // overloaded get() method
    int deep_get() const
    {
        // gets reference and makes
        // a copy when returned
        return this->get();
    }
};


int main()
{
    A a;
    a.get() = 8;  // call non-const method
    a.deep_get(); // indirectly call const method

    B b;
    b.get() = 8;  // call non-const method
    b.deep_get(); // indirectly call const method
}

【问题讨论】:

标签: c++ class constants const-cast


【解决方案1】:

成员函数的常量应该根据以下问题来决定:成员函数在上下文中是用来修改对象的吗?(要么是成员直接修改对象,要么返回一个引用/指向内部数据的指针,以便外部调用者可以修改对象)。如果是,则将其设为非 const,否则将其设为 const。

编译器将正确选择仅在 constness 上不同的重载。但是,在重载决议中不使用返回类型。此外,按值/按引用返回应该仅根据您要返回的预期成本和预期所有权来决定。幸运的是,C++11 通过提供move semantics 让生活变得更轻松。这意味着您可以愉快地按值返回大型数据结构。仅当被引用对象的寿命超过外部调用者时才通过引用返回。

在我看来,您的int&amp; get() 应该重命名为void set(int),并且您可以将您的int get() const 拆分为一个计算助手和一个适当的get()

class C
{
    int val_;
public:
    void modify()   { /* some expensive computation on val_ */ }
    int get() const { return val_; }
    void set(int v) { val_ = v_; }
};

或者,如果您想保留get() 功能,您可以这样做

class D
{
int val_;
public:
    void modify()    { /* some expensive computation on val_ */ }
    int get() const  { modify(); return val_; }
    int& get()       { modify(); return val_; } // no const-cast needed
};

【讨论】:

  • 也许我的代码太少了。想象一下 get() 真的是 get(string) 并且有很多(可能是递归的)计算是用字符串完成的,以确定要返回哪个对象。我希望返回对(公共)成员对象的引用,但也能够从 const 方法调用相同(或重载)的方法。
  • @Johann 同样的事情:编写一个辅助函数来执行计算,并编写 2 个get() 函数来返回每个调用内部计算辅助函数的对象状态。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-28
  • 1970-01-01
  • 2011-06-24
  • 2020-11-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多