【问题标题】:C++ , how to return a reference to the member variable from iteratorC++,如何从迭代器返回对成员变量的引用
【发布时间】:2012-12-03 16:35:15
【问题描述】:

从 std::vector 派生出以下 B 类

class B: public std::vector <unsigned int>
{
    public:
            B() : std::vector <unsigned int> ( 0 ) {}
};

还有一个A类如下:

class A
{
    private:        
            B b;    
    double x;

public:
    B & getB () {return b;}
    B const & getB() const {return b;}

    bool operator() ( const A & a ) const
            {
                    return a < a.x;
            }
};

为什么不可能从其迭代器返回对存储在 std::list 中的某个对象 A 的变量 b 的引用(以及如何做到这一点)?

int main ()
{
std::set <A > alist;
std::set <A> ::iterator i_alist = alist.begin();

for (; i_alist != alist.end(); i_list++)
{
    B &il = (*i_alist).getB(); //Compiler error
    B &il2 = i_alist->getB(); //Compiler error

    il.push_back(10);   //Modify il and concurrently B
}
} 

编译器错误:

Error   1   error C2440: 'initializing' : cannot convert from 'const B' to 'B &'    d:\test.cpp

感谢您的帮助...

编辑问题

使用 const_cast 的可能解决方案:

B &il2 = const_cast <B&> ( i_alist->getB() );

【问题讨论】:

    标签: c++ vector reference iterator set


    【解决方案1】:

    这与std::vector 关系不大,而与std::set 关系密切。您将对象存储在std::set 中。 std::set 的元素不能从外部修改。一旦将元素插入到集合中,就无法更改它。

    出于这个原因,std::set::iterator 可能(并且将)评估为一个常量对象,即使它不是 const_iterator(语言规范实际上允许 std::set::iteratorstd::set::const_iterator 引用相同的类型,但不需要它)。 IE。在您的示例中,*i_listconst A 类型的 const 限定对象。编译器将调用getBconst 版本,它返回const B &amp;。您显然希望突破这种 constness,期望调用 getB 的非 const 版本。

    没有办法绕过它,除非您决定使用某种 hack(const_cast 等)从 set 元素中删除 const 性,从而使编译器调用非 const 版本的 getB

    基于const_cast 的破解解决方案看起来像

    B &il = const_cast<A &>(*i_alist).getB();
    

    或者您可以稍后从返回的B 引用中删除常量

    B &il = const_cast<B &>((*i_alist).getB());
    B &il2 = const_cast<B &>(i_alist->getB());
    

    【讨论】:

    • 就我个人而言,我认为 C++ 标准强制 set 键上的常量是一个错误。我经常在一个集合中有复杂的对象,它们的内容可以在不影响排序的情况下更改。这不是 C++11 引入的变化吗?
    • @AndreyT:有什么办法可以让存储在 std::set 中的对象从外部被修改?例如使用 const_cast?
    • @Mark Ransom:关键的常量是有道理的,但是修改对象的非关键部分的需求确实经常出现。是的,我同意,设置元素应该是可修改的。
    • @MarkRansom,但std::set 如何保证您的更改不会影响订购?
    • @aleguna:它不会(可能是调试实现中的一些断言)。它只会说“知道自己在做什么,并自担风险”。
    【解决方案2】:

    您的示例有些地方看起来很奇怪:

    1. 永远不要从std::vector 派生。它不是为这种用途而设计的。通常没有理由这样做,除了懒惰,即避免打字。
    2. A::operator() 是干什么用的?为您正在使用的std::set 提供比较器似乎有些奇怪。通常你不会仅仅因为你把它塞进std::set某处就改变一个类。如果您真的希望能够比较您的 A(通常,不仅仅是为了集合),然后写一个适当的免费 bool operator&lt;(A const&amp;, A const&amp;); 如果它只是为了集合,请在您使用集合的地方编写一个自定义比较器。 (该比较器不应该需要访问 A 的私人信息)
    3. A::x 是做什么用的?仅用于比较还是仅用于集合内的比较?如果只是这样,请考虑使用std::map&lt;double, A&gt; 甚至std::map&lt;double, B&gt;,在其中将 x 作为键,将实际对象作为值。

    你看,我问了很多未解决的问题,也许解决方案(使用地图)甚至不适合你的问题。那是因为您没有向我们展示您拥有的真实代码,而只是向我们展示了一些名称毫无意义的示例。因此,我们只看到您尝试的工作,而不是您真正想用您的代码实现的内容。

    PS:也许你一开始甚至不需要一个有序的容器,将所有的对象都塞进std::vector然后std::sort就足够了。取决于您真正拥有的对象类型(您的示例中的 A 复制/交换成本很低)以及您使用容器的方式 - 插入如何与循环交错等等。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-03
      相关资源
      最近更新 更多