2010-10-28 132 views
10

我想知道是否可以从const成员函数中调用非const成员函数。在下面的例子中,First给出了一个编译器错误。我明白为什么会出现错误,我想知道是否有办法解决此问题。从const成员函数调用非const成员函数

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

    int& Second() 
    { 
     return m_bar; 
    } 

    int m_bar; 
} 

我真的不想讨论这样做的智慧,我很好奇,如果它甚至可能。

+3

你不是第一个:http://stackoverflow.com/questions/856542/elegant-solution-to-duplicate-const-and-non-const-getters – 2010-10-28 21:13:27

+0

谢谢直到,没有出现我的搜索 – Steve 2010-10-28 21:26:48

回答

28
return (const_cast<Foo*>(this))->Second(); 

然后安静地哭泣。

+0

如果这些函数具有相同的名称,该怎么办? const int&GetBar()const; int&GetBar(); – phandinhlan 2015-04-24 22:15:56

+0

你可以重载一个const的函数,所以它会简单的工作。 – user3063349 2016-05-10 10:21:59

10

这是可能

const int& First() const 
{ 
    return const_cast<Foo*>(this)->Second(); 
} 

int& Second() { return m_bar; } 

我不会推荐;这是丑陋和危险的(任何使用const_cast是危险的)。

这是更好地移动尽可能多的通用功能,你可以进入辅助功能,然后让const和non-const成员函数每个做尽可能少的工作,因为他们需要。

对于这样一个简单的访问器,它就像从两个函数调用一个函数一样简单到return m_bar;

+0

或者只是把'int&Second()'变成'int&Second()const'。 non-'const'成员函数在调用'Second()'时没有问题,但现在'const'成员函数也可以在没有任何jiggery-pokery的情况下调用它。 – 2010-10-28 21:30:21

+0

@Jeremy:你认为我们如何返回一个非const引用给成员呢? – GManNickG 2010-10-28 21:32:22

+0

@GMan:Touché。你不能没有声明'm_bar'作为'mutable int'。 @Fred Larson的推荐是相当不错的,但是它带领的方向 - 一旦“const”修改并且一旦没有 - 就不会那么愉快地编写每个有福的访问者两次。 – 2010-10-28 21:39:16

3

通过的const的定义,函数不应修改一个对象的状态。但是如果它调用另一个非const成员,那么该对象的状态可能会发生变化,因此它是不允许的。

我知道你说你不想听到这个,但我认为这是别人在问题所发生的重要。

2

超载对const

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

您可以添加此方法并保持原有的非const版本。

1

迭代器是在此类似,使一个有趣的研究。

常量迭代器通常是“非常量”迭代器的基础,并且您经常会发现const_cast<>()或C风格强制转换用于从子类中的带有访问器的基类中丢弃常量。

编辑: 评论是

我有一个拉链迭代器,其中常量一个从非const

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

说你有一些算法把你的拉链迭代器,一个const迭代器传递给非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; 
+0

我倾向于将迭代器作为模板类编写,并使用类型特征来操纵成员函数的常量;它避免了'const_cast'的需要,并使得代码更易于阅读。 – 2010-10-28 22:22:57

+0

听起来很有意思,但它是否允许在可能使用const_iterator的地方使用迭代器?我正在对我见过的stl(s)进行这个原始观察 - 主要针对MSVC。 – 2010-10-28 22:38:56

+0

这实际上是我的用例。我有一个zip迭代器,其中const从非const继承。 @詹姆斯,你能回答这个问题的类型特征答案吗?我真的很感兴趣,如果可能的话不要这样做 – Steve 2010-10-29 01:56:03

0

我发现自己试图调用这是继承了一个非const成员函数的快速轮廓,但因为我是API的实际常量使用。最后,我决定采用不同的解决方案:重新协商API,以便我继承的功能正常。

协商对其他人的功能所做的更改并不总是可能的,但在可能的情况下这样做似乎比需要使用const_cast更清洁,更好,并且也会使其他用户受益。

3

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

class CFoo 
{ 
public: 
    CFoo() {m_Foo = this;} 
    void tee(); 

    void bar() const 
    { 
     m_Foo->m_val++; // fine 
     m_Foo->tee(); // fine 
    } 
private: 
    CFoo * m_Foo; 
    int m_Val; 

}; 

这实际上取消了const成员函数的目的,所以最好不要在设计一个新类时做。知道有一种方法可以做到这一点并不是什么坏事,特别是它可以用来解决那些在const member函数的概念上没有很好设计的旧类。

+0

真是个诡计! ...我会用它:) – Olumide 2016-06-17 11:36:12