0

考虑到头文件中的以下内容,我有一个与命名空间有关的小问题:

namespace A {
    namespace B {
        void SetMemberValue(double value) { _member = value; }
        double FunctionThatUsesMember(double a) { return a * _member; }
        double AnotherFuncThatUsesMember(double a) { return a / _member; }
        static double _member = 0.01;
    }
}

我不希望用户能够更改_membervia的值A::B::_member = some_value。在阅读了未命名的命名空间后,我将其更改为:

namespace A {
    namespace B {
        void SetMemberValue(double value) { _member = value; }
        double FunctionThatUsesMember(double a) { return a * _member; }
        double AnotherFuncThatUsesMember(double a) { return a / _member; }
        namespace {
            double _member = 0.01;
        }
    }
}

这会强制用户使用提供的 mutator 函数并且效果很好,除了一个问题:

如果用户继续使用:A::B::_member = some_value代码没有编译、链接、运行失败;该语句被忽略,使用默认值0.01可能导致运行时错误或“OMG WTF IS WRONG BBQ!!1!!” 时刻。(虽然我不确定,但声明没有失败可能是 MSVC++ 和 VS2010 的问题。)

问题:有没有办法让代码在A::B::_member = some_value错误使用时以某种方式大声失败?

4

1 回答 1

2

首先,请注意您_member在每个翻译单元中获得不同的版本!我不确定这是否是故意的。

如果你真的想要一个_member在你的程序中并且你不希望用户访问一个特定的全局变量,你不应该让它在标题中可见!将其放入源代码并提供在那里访问它的函数:

// some-module.h
double getValue();
void   setValue(double value);

// some-module.cpp
#include "some-module.h"
static double value(0.01);
double getValue() { return value; }
void   setValue(double value) { ::value = value; }

我省略了名称空间,因为它们实际上并不重要。您可以使用未命名的命名空间而不是static在翻译单元内部,但这并没有太大的区别,真的。

如果您声称额外的函数调用是不可接受的并且所有内容都必须在标头中,您可以将 value 设为类的私有成员。您仍然需要将其包装到一个函数中以避免重复的符号。如果您还将该类包装到一个未命名的命名空间中,则每个翻译单元也可以拥有一个版本的值:

#if ONE_VALUE_PER_TRANSLATION_UNIT
namespace {
#endif

class Value
{
    static double& value() { static double rc(0.01); return rc; }
    friend double getValue();
    friend void   setValue(double value);
};
double getValue() { return Value::value(); }
void   setValue(double value) { Value::value() = value; }

#if ONE_VALUE_PER_TRANSLATION_UNIT
}
#endif

显然,您可以在所有这些情况下添加更多访问值的函数。我刚刚演示了使用简单的非成员函数getValue()setValue(). 你真正暴露的东西取决于你。

于 2013-08-29T21:50:42.357 回答