5

考虑以下类成员:

std::vector<sim_mob::Lane *>  IncomingLanes_;

如果我的 Lane 对象,上述容器应存储指向某些对象的指针。我不希望使用此变量作为参数的子程序能够修改 Lane 对象。同时,我不知道在哪里放置不会阻止我填充容器的 'const' 关键字。

你能帮我解决这个问题吗?

谢谢你,问候瓦希德

编辑: 根据我到目前为止得到的答案(非常感谢他们)假设这个样本:

#include <vector>
#include<iostream>
using namespace std;

class Lane
{
private:
    int a;
public:
    Lane(int h):a(h){}
    void setA(int a_)
    {
        a=a_;
    }
    void printLane()
    {
        std::cout << a << std::endl;
    }
};

class B
{

public:
    vector< Lane const  *> IncomingLanes;
    void addLane(Lane  *l)
    {
        IncomingLanes.push_back(l);
    }

};

int main()
{
    Lane l1(1);
    Lane l2(2);
    B b;
    b.addLane(&l1);
    b.addLane(&l2);
    b.IncomingLanes.at(1)->printLane();
    b.IncomingLanes.at(1)->setA(12);
    return 1;
}

我的意思是:

b.IncomingLanes.at(1)->printLane()

应该可以毫无问题地在 IncomingLanes 上工作并且

b.IncomingLanes.at(1)->setA(12)

不应该被允许。(在上面的例子中,提到的两种方法都不起作用!)

除了解决问题,我还寻求良好的编程实践。因此,如果您认为上述问题有解决方案但方法不好,请告诉我们。谢谢你

4

7 回答 7

3

先绕道:在容器中使用智能指针,shared_ptr而不是原始指针。这将使您的生活变得轻松很多。

通常,您要查找的内容称为设计常量,即不修改其参数的函数。这可以通过传递参数来实现const-reference。此外,如果它是一个成员函数,则创建该函数const(即成为此函数thisconst范围内,因此您不能使用它this来写入成员)。

如果不了解您的班级的更多信息,就很难建议您使用const-references 到车道的容器。这将使插入lane对象变得困难——这是一次性的事情,只能通过 ctor(s) 中的初始化列表来实现。

一些必须阅读:

编辑:代码示例:

#include <vector>
#include <iostream>
//using namespace std; I'd rather type the 5 characters

// This is almost redundant under the current circumstance
#include <vector>
#include <iostream>
#include <memory>
//using namespace std; I'd rather type the 5 characters

// This is almost redundant under the current circumstance
class Lane
{
private:
    int a;
public:
    Lane(int h):a(h){}
    void setA(int a_) // do you need this?
    {
        a=a_;
    }
    void printLane() const // design-const
    {
        std::cout << a << std::endl;
    }
};

class B
{    
    // be consistent with namespace qualification
    std::vector< Lane const * > IncomingLanes; // don't expose impl. details
 public:
    void addLane(Lane const& l) // who's responsible for freeing `l'?
    {
        IncomingLanes.push_back(&l); // would change
    }
    void printLane(size_t index) const
    {
#ifdef _DEBUG 
        IncomingLanes.at( index )->printLane();
#else
        IncomingLanes[ index ]->printLane();
#endif
    }        
};

int main()
{
    Lane l1(1);
    Lane l2(2);
    B b;
    b.addLane(l1);
    b.addLane(l2);
    //b.IncomingLanes.at(1)->printLane(); // this is bad
    //b.IncomingLanes.at(1)->setA(12); // this is bad
    b.printLane(1);

    return 1;
}

此外,正如 Matthieu M. 所建议的:

共享所有权更加复杂,因为很难分辨谁真正拥有该对象以及何时释放它(这是性能开销之上的)。所以 unique_ptr 应该是默认选择,而 shared_ptr 是最后的选择。

请注意,unique_ptrs 可能需要您使用std::move. 我正在更新要使用的示例pointer to const Lane(一个更简单的入门界面)。

于 2012-05-03T07:59:51.290 回答
2

你可以这样做:

std::vector<const sim_mob::Lane *>  IncomingLanes_;

或者这样:

std::vector<sim_mob::Lane const *>  IncomingLanes_;

C/C++中,const typename * 和typename const * 含义相同。

更新以解决更新的问题:

如果你真的需要做的就是

b.IncomingLanes.at(1)->printLane()

那么你只需要printLane像这样声明:

void printLane() const // Tell compiler that printLane doesn't change this
  {
  std::cout << a << std::endl;
  }
于 2012-05-03T07:59:33.893 回答
1

我怀疑您希望对象能够修改元素(即,您不希望元素真正成为const)。相反,您希望非成员函数只能获得对 的只读访问std::vector(即,您希望禁止来自对象外部的更改)。

因此,我不会放在const任何地方IncomingLanes_。相反,我将公开IncomingLanes_为一对std::vector<sim_mob::Lane *>::const_iterators(通过称为 and 之类的方法GetIncomingLanesBegin()GetIncomingLanesEnd()

于 2012-05-03T08:00:51.150 回答
1

你可以这样声明:

std::vector<const sim_mob::Lane *>  IncomingLanes_;

您将能够从数组中添加或删除项目,但您希望能够更改项目,请参见下文

   IncomingLanes_.push_back(someLine); // Ok
   IncomingLanes_[0] = someLine; //error
   IncomingLanes_[0]->some_meber = someting; //error
   IncomingLanes_.erase(IncomingLanes_.end()); //OK
   IncomingLanes_[0]->nonConstMethod(); //error
于 2012-05-03T08:10:49.393 回答
0

如果您不希望其他例程修改 IncomingLanes,但您确实希望能够自己修改它,只需const在您调用的函数声明中使用。

或者,如果您无法控制这些功能,那么当它们是外部的时,不要让它们直接访问 IncomingLanes。将 IncomingLanes 设为私有并为其提供一个 const getter。

于 2012-05-03T07:59:37.463 回答
0

如果不将指针也存储在向量 const 中,我认为你想要的东西是不可能的。

 const std::vector<sim_mob::Lane*> // means the vector is const, not the pointer within it
 std::vector<const sim_mob::Lane*> // means no one can modify the data pointed at.

充其量,第二个版本可以满足您的需求,但是您将在整个代码中使用此构造,只要您想修改数据:

 const_cast<sim_mob::Lane*>(theVector[i])->non_const_method();

您是否考虑过不同的类层次结构,其中 sim_mob::Lane 的公共接口是 const 而 sim_mob::Really_Lane 包含非常量接口。那么向量的用户如果不使用dynamic_cast就不能确定“车道”对象是“真实的”吗?

于 2012-05-03T08:04:36.827 回答
0

在我们得到const好处之前,您应该首先使用封装

不要暴露于外部世界,它会变得容易得多vector

这里的弱 (*) 封装就足够了:

class B {
public:
    std::vector<Lane> const& getIncomingLanes() const { return incomingLanes; }

    void addLane(Lane l) { incomlingLanes.push_back(l); }

private:
    std::vector<Lane> incomingLanes;
};

以上是最简单的,但达到了目标:

  • 类的客户不能修改vector自身
  • 类的客户不能修改vector内容(Lane实例)

当然,班级可以vector完全访问内容并随意修改。

你的新main程序变成:

int main()
{
    Lane l1(1);
    Lane l2(2);
    B b;
    b.addLane(l1);
    b.addLane(l2);
    b.getIncomingLanes().at(1).printLane();
    b.getIncomingLanes().at(1).setA(12); // expected-error\
        // { passing ‘const Lane’ as ‘this’ argument of
        //   ‘void Lane::setA(int)’ discards qualifiers }
    return 1;
}

(*) 这在某种意义上是的,即使属性本身没有暴露,因为我们在实践中将它的引用提供给外部世界,客户端并没有真正被屏蔽。

于 2012-05-03T09:21:56.300 回答