2013-08-01 93 views
6

大概不是。这里是我的使用情况:指针是否可以指向const空类或非const类?

我有两个类A & B.

class A 
{ 
    B *b_; 
};   

class B 
{ 
public: 
    B(): b_string_("") {}; 

private:  
    std::string b_string_; 
}; 

我想B_总是指向一个B对象。我希望b_指向一个“空白”B对象而不是nullptr,这样我总是可以以定义的方式对* b_进行取消引用来获得一个空b_-> b_string。所以我想我会创建一个全局的“空B对象”:const B null_b。但我不能(自然)使用一个构造函数:

A(): b_(&null_b) {}; 

因为B_不能指向一个const变量。如果不是“空B对象”,b_需要指向可变B对象。

使全局非常量解决问题,但我想保护常量,所以我可以保证“空对象”永远不会改变。

FWIW,这涉及一个大型项目,其中b_指向另一个类中B对象的向量。我可以向该矢量添加一个空B对象,但这会让我觉得它很糟糕。

有没有解决我的问题的方法或模式?

+1

我可能不应该建议这个,但... const_cast? – Borgleader

+0

您是否在寻找Flyweight?但是,请记住,所有的指针在逻辑上会是const – sehe

+0

@Borgleader这对此有何帮助?你不能在运行时决定const_cast指针为const(如果它指向你的Nil对象) – sehe

回答

5

而不是持有一个指向B对象的指针,而是用虚方法创建一个基类并存储指向它的指针。从中导出B类和Null_B类,但不要让Null_B上的方法进行修改。现在,即使您的Null_B对象不是const,也无所谓。

作为额外的保护层,您可以尝试修改对象引发的异常,以便检测并找到您的逻辑错误。

+1

一个工作示例(除了直接从B获得Null_B之外):https://ideone.com/m5ezfh – Bill

+0

@bill和markransom - 谢谢你的工作。感谢代码比尔!它立即变得明显。 :) –

1

嗯,也许它完全没有关系,但是......你可以使用B的实例而不是指向B中的指针吗?这将解决潜在的nullptr解引用问题。如果B太大,那么你可以在它周围创建一个轻量级的包装器,并在A中存储该包装器的实例。如果B是nullptr,包装器将为你提供一些有意义的东西。

+0

不 - 我必须指出在真实项目中这个相当复杂的结构。我不仅需要复制的开销,而且需要更新它而不是复制。 –

+0

感谢您的帮助!我认为,马克和比尔的解决方案本质上是对你所暗示的空对象的简短而甜蜜的包装。 –

3

const对象上不能有“非常量”指针点。不幸的是,使用const_cast删除对象的const将意味着稍后的某些代码可以尝试修改该对象。 (请注意,除非原始对象是非常量,否则它是未定义的行为,因此在技术上,允许编译器在发生这种情况时生成崩溃代码。不幸的是,很多情况下,当对象是某种东西时它不会崩溃比const char *const int []更复杂 - 允许代码在覆盖不想写入的对象后继续运行)。

然而,由于B类有一个b_string_成员是私有的,没有外界的对象可以触摸它,所以你可以确保b_string_任何使用通过虚函数(或多个虚拟函数)来完成,然后派生另一个从B的类中,当代码尝试修改派生对象中的b_string时,虚函数会显示“对不起,你不能这样做”。

+0

const_cast首先是UB,除非你知道指针实际上是可变的 – sehe

+0

是的,我的观点是,如果你抛弃了常量,它不会阻止某人修改它 - 它是UB是一种旁边的指向那个阶段,因为使它成为'const'的原因可能是你不想修改它 - 在大多数系统中它是平均的,它可能不会崩溃,所以它会幸福地与对象一起工作无障碍和奇怪的事情发生。 –

+1

修改它可能会很好地崩溃应用程序。事实上,当你** [在平均hello-world级别应用程序中通过'const char *'写入](http://ideone.com/30zoCA)**时,情况就是如此。我想我的观点是“UB永远不会离题” – sehe

相关问题