C++ 从常量成员函数调用非常量成员函数

C++ 从常量成员函数调用非常量成员函数,c++,constants,C++,Constants,我想知道是否可以从常量成员函数调用非常量成员函数。在下面的示例中,首先给出一个编译器错误。我理解它为什么会出错,我想知道是否有办法解决它 class Foo { const int& First() const { return Second(); } int& Second() { return m_bar; } int m_bar; } 我真的不想讨论这样做的智慧,我很好奇这是否可能。可能: c

我想知道是否可以从常量成员函数调用非常量成员函数。在下面的示例中,首先给出一个编译器错误。我理解它为什么会出错,我想知道是否有办法解决它

class Foo
{
   const int& First() const
   {
         return Second();
   }

   int& Second()
   {
        return m_bar;
   }

   int m_bar;
}
我真的不想讨论这样做的智慧,我很好奇这是否可能。

可能:

const int&First()常量
{ 
返回const_cast(this)->Second();
}
int&Second(){return m_bar;}
我不建议这样做;这是丑陋和危险的(任何使用
const_cast
都是危险的)

最好将尽可能多的常用功能移到助手函数中,然后让您的常量和非常量成员函数各自完成所需的少量工作

对于这样一个简单的访问器,
返回m_条同样容易
返回(const_cast(this))->Second();
return (const_cast<Foo*>(this))->Second();

然后安静地哭。

根据
const
的定义,函数不应该修改对象的状态。但是,如果它调用另一个非常量成员,对象的状态可能会更改,因此它是不允许的


我知道你说过你不想听这件事,但我认为这对其他人来说是很重要的,因为这个问题发生了。

const
上的重载:

const int& Second() const
{
    return m_bar;
}

您可以添加此方法并保留原始的非常量版本。

迭代器在这方面类似,并进行了有趣的研究

常量迭代器通常是“非常量”迭代器的基础,您经常会发现
const_cast()
或C样式的强制转换用于从基类中丢弃常量,并在子类中使用访问器

编辑: 评论是

我有一个zip迭代器,其中常量1继承自非常量

这通常是错误的继承结构(如果你说的是我认为你是的话),原因是孩子不应该比父母限制少

假设您有一些算法使用zip迭代器,将常量迭代器传递给非常量迭代器是否合适

如果您有一个const容器,则只能向它请求一个const迭代器,但是const迭代器是从迭代器派生的,因此您只需使用父容器上的功能即可进行非const访问

下面是一个建议继承传统stl模型的简要概述

class ConstIterator: 
    public std::_Bidit< myType, int, const myType *, const mType & >
{
  reference operator*() const { return m_p; }
}

class Iterator : public ConstIterator 
{
  typedef ConstIterator _Mybase;
  // overide the types provided by ConstIterator
  typedef myType * pointer;
  typedef myType & reference;

  reference operator*() const
  { 
    return ((reference)**(_Mybase *)this);
  }
}

typedef std::reverse_iterator<ConstIterator> ConstReverseIterator;
typedef std::reverse_iterator<Iterator> ReverseIterator;
类转换器:
公共标准::_Bidit
{
引用运算符*()常量{return m_p;}
}
类迭代器:公共迭代器
{
typedef conditerator_Mybase;
//超出Conditor提供的类型
typedef myType*指针;
typedef myType&reference;
引用运算符*()常量
{ 
返回((参考)**(_Mybase*)本);
}
}
typedef std::反向迭代器ConstReverseIterator;
typedef std::反向迭代器反向迭代器;

我发现自己试图调用一个继承的非常量成员函数,但由于我使用的API,该函数实际上是常量。最后,我决定采用另一种解决方案:重新协商API,使我继承的函数正确地保持常量


不可能总是协商对其他函数的更改,但在可能的情况下这样做似乎比需要使用const_cast更干净、更好,这也有利于其他用户。

const成员方法的限制来自编译时。如果你能愚弄编译器,那么是的

类CFoo
{ 
公众:
CFoo(){m_Foo=this;}
空三通();
空条()常数
{ 
m_Foo->m_val++;//很好
m_Foo->tee();//很好
}
私人:
CFoo*m_Foo;
国际货币基金组织;
};

这实际上取消了const成员函数的用途,因此在设计新类时最好不要这样做。知道有一种方法可以做到这一点是无害的,特别是它可以作为这些旧类的一种解决方法,这些旧类不是根据const成员函数的概念精心设计的。

你不是第一个:谢谢,直到我的搜索中没有出现这种方法,或者只是将
int&Second()
转换为
int&Second()const
。非
const
成员函数调用
Second()
不会有问题,但现在
const
成员函数也可以调用它,而无需任何诡计。@Jeremy:那么,你认为我们如何将非const引用返回给成员?@GMan:Touché。如果不将
m_bar
声明为
mutable int
,则无法执行此操作@弗雷德·拉森的建议很好,但它的方向——写每一个受祝福的访问者两次,一次
const
——修改,一次不修改——并不是很乐观。@Jeremy:在大多数情况下(不是所有情况,但大多数情况下),不需要一个非const访问者(至少这是我的经验)。即使您确实需要这两个函数,因为您无论如何都必须编写这两个函数,编写
返回m_条通常不会带来太多额外负担。问题是zip迭代器的常量版本中zip迭代器接口的继承,因此它不像示例中建议的那样简单。我倾向于将迭代器编写为模板类,并使用类型特征来操纵成员函数的常量;它避免了
const_cast
的需要,使代码更易于阅读。听起来很有趣,但是它是否允许在可能使用const_迭代器的地方使用迭代器?我对我所看到的stl做了一个原始的观察,主要是针对MSVC的stl。这实际上是我的使用案例。我有一个zip迭代器,其中常量1继承自非常量@詹姆斯,你能用你的答案回答这个问题吗?我真的很有兴趣不这样做,如果possible@Steve:我要试着挖些东西;目前我的电脑上没有我所有的项目。
class ConstIterator: 
    public std::_Bidit< myType, int, const myType *, const mType & >
{
  reference operator*() const { return m_p; }
}

class Iterator : public ConstIterator 
{
  typedef ConstIterator _Mybase;
  // overide the types provided by ConstIterator
  typedef myType * pointer;
  typedef myType & reference;

  reference operator*() const
  { 
    return ((reference)**(_Mybase *)this);
  }
}

typedef std::reverse_iterator<ConstIterator> ConstReverseIterator;
typedef std::reverse_iterator<Iterator> ReverseIterator;