c++ - 常量正确性与非变异集合的混淆

标签 c++ const-correctness

假设我有一个 Widget类和集合 Widget s:

class Widget
{
public:
    void mutate() {}
};

class WidgetCollection
{
private:
    std::vector<Widget> vec;

public:
    Widget* findNiceWidget() { /*...*/ }
    const Widget* findNiceWidget() const { /*...*/ }
};

WidgetCollection::findNiceWidget()允许访问 Widget 之一集合中满足某些条件的 s。

现在,我有课 WidgetTags它允许将标签分配给 Widget s。标签不属于 Widget s,但存储在此类的外部:

class Tag {};

class WidgetTags
{
private:
    std::multimap<const Widget*, Tag> tags;

public:
    void addTag(const Widget* w, Tag t) { /*...*/ }
    std::vector<const Widget*> getWidgetsWithTag(Tag t) const { /*...*/ }
};

该类仅处理指向 const Widget 的指针因为它永远不会改变任何 Widget ,它只是将附加数据与它们相关联。

然后我介绍了三个函数来处理这些结构。

// Takes Widgets from the WidgetCollection and assigns tags to them in an instance of WidgetTags
void tagWidgets(const WidgetCollection& wc, WidgetTags& wt)
{
    Tag niceTag;
    wt.addTag(wc.findNiceWidget(), niceTag);
}

// Prints all Widgets which have the niceTag tag
void printNiceWidgets(const WidgetTags& wt)
{
    Tag niceTag;
    for (auto w : wt.getWidgetsWithTag(niceTag))
        std::cout << w;
}

// Calls a mutating function on all Widgets which have the niceTag tag
void mutateNiceWidgets(const WidgetTags& wt)
{
    Tag niceTag;
    for (auto w : wt.getWidgetsWithTag(niceTag))
        w->mutate();
}

我现在面临的问题是mutateNiceWidgets()显然不能打电话mutate()因为它只能对 WidgetTags 返回的小部件具有常量访问权限,即使我通过了WidgetTags作为非常量引用。 为了解决这个问题,我必须重写 WidgetTags存储指向非常量 Widget 的指针s 并为他们提供一个非常量 getWidgetsWithTag() 。但如果我这样做,那么WidgetTags::addTag()也必须接受指向非常量的指针。 如果我这样做,那么我会在 tagWidgets() 中遇到问题,然后必须接受对 WidgetCollection 的非常量引用,在我看来这是不正确的,因为它不应该改变集合(事实上,调用代码甚至可能无法提供非常量引用)。

我对在这种情况下应该如何应用 const 正确性感到困惑。

在我的用例中,所有 WidgetWidgetCollection 管理和拥有。因此从理论上讲,您应该被授予对 Widget 的非常量访问权限。如果您对整个WidgetCollection有非常量的访问权限,无论您如何获得Widget 。 这让我考虑实现这样的事情:

class WidgetCollection
{
    // ...

    Widget* makeNonConst(const Widget* w)
    {
        return const_cast<Widget*>(w);
    }
};

并重写mutateNiceWidgets() :

void mutateNiceWidgets(WidgetCollection& wc, const WidgetTags& wt)
{
    Tag niceTag;

    for (auto w : wt.getWidgetsWithTag(niceTag))
        wc.makeNonConst(w)->mutate();
}

但这感觉非常错误。

任何关于如何正确选择什么应该是 const 和什么不应该是 const 的想法都值得赞赏。

最佳答案

您使用指针有两个原因;身份和访问控制。

从这里开始:

struct WidgetId;

它现在是抽象的(不是虚拟抽象;但我们没有指定其中的内容。但是请使其成为常规值类型)。 WidgetId 唯一地命名一个小部件。

现在WidgetTags是身份和标签之间的多重bimap。

WidgetId findNiceWidget() const { /*...*/ }
const Widget* getWidget(WidgetId) const { /*...*/ }
Widget* getWidget(WidgetId) { /*...*/ }
WidgetId getWidgetId(Widget const*) const { /*...*/ }

你的问题就消失了。

现在,WidgetId 可以只是一个整数,或者一个 Widget const*,或者任何内部的东西。

但是通过将访问权限与身份分开,您的问题就消失了。如果小部件存储不那么简单,最终用户也不会注意到。

关于c++ - 常量正确性与非变异集合的混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65534139/

相关文章:

c++ - 如何从 const 方法调用非 const 方法?

c++ - 为什么我不能在下面的代码中访问 A 类函数?

c++ - 如何在设置 QStyleSheet 后获取 QWidget 背景颜色

c++ - 每个 libstdc++ 版本的 `__GLIBCXX__` 值

c++ - 在成员函数末尾添加 const 是否是一种好习惯 - 在适当的情况下?

c++ - const 正确性和返回值 - C++

c++ - 更换场景后,Schedule 方法不再起作用

c++ - 不能在 C++ 中的另一个对象中更改对象的属性

c++ - Qt4 C++ 指向 const QList of pointers 的指针

C++ const 正确性和 const 成员