代码之家  ›  专栏  ›  技术社区  ›  V_D_R

C++:如何处理需要修改的const对象?

  •  6
  • V_D_R  · 技术社区  · 15 年前

    我在过去常说的代码中有一个位置

    const myType & myVar = someMethod();
    

    问题是:

    • someMethod()返回 const myType

    • 稍后,我需要能够更改myvar,方法是在对象处于无效状态时分配一个默认值。所以我需要 myVar 非常量。

      1. 我想我需要 Myvar公司 也不能作为参考,对吗?例如。 myType myVar ?

      2. 什么是C++“正确”的方式来做这个const到非const?静态浇铸?词汇转换?还有别的吗?

    我可以使用Boost的词法演员表,所以我不介意这样做,但我更喜欢非- 促进 解决方案,如果它结束了,我不允许使用 促进 .

    谢谢!

    7 回复  |  直到 15 年前
        1
  •  5
  •   divegeek    15 年前

    我不会使用const-cast解决方案,复制对象可能不起作用。相反,为什么不有条件地分配给另一个常量引用呢?如果myvar有效,请指定它。如果没有,请指定默认值。下面的代码可以使用这个新的常量引用。一种方法是使用条件表达式:

    const myType& myOtherVar = (myVar.isValid() ? myVar : defaultVar);
    

    另一种方法是编写一个接受常量引用(myvar)并根据myvar的有效性返回myvar或defaultvar的函数,并将返回值从中分配给myothervar。

    第三种方法是使用常量指针,将其指向myvar的地址或默认对象的地址。

        2
  •  9
  •   MSalters    15 年前

    你可能不需要任何演员。如果你能复制 T ,然后您也可以复制 T const 排除病理病例。复印件 T常数 不需要是 T常数 本身。

    myType myVar = someMethod(); // Creates a non-const copy that you may change.
    
        3
  •  1
  •   Lou Franco    15 年前
    const_cast<type without const>()
    

    但是,确实 someMethod() 真回 const myType 是吗?如果是这样,您将引用一个临时的——它将被销毁,而您的引用将是坏的。更改 myVar 到非引用(所以它是副本)——在这种情况下不需要声明它是常量。或者,如果 一些方法() 返回引用,使用 const_cast 如果你必须的话(但是你正在改变一些 someMethod 思想不会改变)。

        4
  •  1
  •   hasen    15 年前

    没有“C++”的方式(不仅如此,而且对任何事情)。

    坏方法是使用 const_cast ,但行为随后将未定义(请阅读:不要这样做)。

    您应该做的是复制对象,然后修改副本。这是唯一的 适当的 处理不可变对象的方法。

        5
  •  0
  •   JaredPar    15 年前

    尝试以下操作

    myType& mutableMyVar = const_cast<myType&>(myVar);
    

    不过,一般来说,删除const是个坏主意。调用方方法返回了对它认为将被视为常量的变量的引用。如果您通过删除常量和修改变量违反了这个假设,那么您可以将任一对象置于有效状态。

    在你的特定案件中,这可能是合法的,但一般来说,这是必须避免的。

        6
  •  0
  •   VNarasimhaM    15 年前

    您可以使用复制构造函数或某些赋值运算符从const对象创建一个对象,然后对其进行修改。

    但我认为您最好先看看函数为什么返回const类型。它被宣布为警察是有原因的。如果你非常确定这就是你想要的,你可以像这样把警察赶走:

    T obj1 = const_cast<T&> (obj); 
    
        7
  •  0
  •   UncleBens    15 年前

    什么是C++“正确”的方式来做这个const到非const?静态浇铸?词汇转换?还有别的吗?

    没有C++的方法。出于某种原因,该类的作者决定您不应该能够通过此方法修改实例。

    如果你是作者,你可以让它返回一个非常量引用。但是这些仍然是可疑的,除非类真的没有业务对您隐藏它(例如,vector不隐藏 什么 它为你保留,只是隐藏 怎样 它为你保存东西)。

    更好的方法(取决于这一切的意义)也可能是不公开成员进行外部操作,而是提供一个为您执行此操作的方法。例如:

    class BadPosition
    {
        int x, y;
     public:
        int& get_x() { return x; }
        int& get_y() { return x; }
        //...
    };
    
    BadPosition p;
    p.get_x() += 1;
    p.get_y() += -1;
    
    class BetterPosition
    {
        int x, y;
     public:
        void move(int x_inc, int y_inc) { x += x_inc; y += y_inc; }
        //...
    };
    
    BetterPosition p;
    p.move(1, -1);
    

    如果您以后需要这样做以使类处于有效状态,那么可以考虑让它的构造函数这样做。如果您不能做到这一点,那么至少提供一个init()方法,这样就不会使这样一个复杂的类完全依赖于被外部操纵成可用的东西。

    当然,也可能有其他不需要强制转换的方法,例如,您可以创建一个副本,修改该副本,然后使用修改后的副本将整个实例替换为另一个实例(假设这足以构造它):

    X x;
    ...
    Y y = x.get();
    y.modify();
    x = X(y);
    

    编辑:那么类是按值返回的?在这种情况下,应该没有办法修改类中的实例,因为您得到的只是一个副本。您可以用一个常量引用来引用它,但是即使您放弃了该引用的常量,您仍然在引用一个临时的常量。

    我上面的回答假设它返回了一个常量引用,因为这似乎是一个更明智的做法(我没有看到人们经常经过 康斯特 价值,尽管可能有人强烈推荐它)。