考虑以下类成员:
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) - &GT; printLane()
应该在没有问题的IncomingLanes上工作
b.IncomingLanes.at(1) - &GT;组A(12)
不应该被允许。(在上面的例子中,所提到的两种方法都不起作用!)
除了解决问题之外,我也在寻求良好的编程实践。因此,如果你认为上述问题有一个解决办法,但方法不好,请让我们都知道。 Thaks agian
答案 0 :(得分:3)
首先绕道而行:使用智能指针shared_ptr
而不是容器内的原始指针。这将使你的生活变得轻松起来。
通常,您要查找的内容称为design-const,即不修改其参数的函数。通过const-reference
传递参数,实现这一点。此外,如果它是成员函数,则函数const
(即this
在此函数的范围内变为const
,因此您无法使用this
向成员写入)。
在不了解您的课程的情况下,很难建议您使用const-reference
s的容器进行通道。这将导致插入lane
对象变得困难 - 一次性事件,只能通过ctor中的初始化列表进行。
一些必读:
编辑:代码示例:
#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_ptr
可能要求您使用std::move
移动它们。我正在更新示例以使用pointer to const Lane
(一个更简单的界面来开始)。
答案 1 :(得分: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;
}
答案 2 :(得分:1)
我怀疑你希望对象能够修改元素(即,你不希望元素真正成为const
)。相反,您希望非成员函数仅获得std::vector
的只读访问权限(即,您希望禁止对象外部的更改)。
因此,我不会将const
放在IncomingLanes_
上的任何位置。相反,我会将IncomingLanes_
公开为一对std::vector<sim_mob::Lane *>::const_iterator
(通过称为GetIncomingLanesBegin()
和GetIncomingLanesEnd()
之类的方法。)
答案 3 :(得分: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
答案 4 :(得分:0)
如果您不希望其他例程修改IncomingLanes,但您希望能够自己修改它,只需在您调用的函数声明中使用const
。
或者,如果您无法控制这些功能,那么当它们处于外部时,请不要直接授予他们访问IncomingLanes的权限。将IncomingLanes设为私有并为其提供const getter。
答案 5 :(得分: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包含非const接口。那么在不使用dynamic_cast的情况下,向量的用户不能确定“Lane”对象是“真实的”吗?
答案 6 :(得分: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;
}
(*)这是弱,即使属性本身未公开,因为我们在实践中向外部世界提供了对它的引用,客户端并没有真正被屏蔽。