命名空间vs.静态类 [英] Namespaces vs. Static Classes

查看:141
本文介绍了命名空间vs.静态类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于我正在开发的项目,我有一堆库类。这些本质上是值的相关函数的集合。这些库中的一些需要在运行时初始化。到目前为止,我一直在使用下面的设计作为解决方案:

For a project I'm working on, I have a bunch of "library classes". These are essentially collections of related functions of values. Some of these libraries need to be "initialized" at run-time. So far, I've been utilizing the design below as a solution:

// Filename: Foo.h
namespace my_project
{
namespace library
{
class Foo
{
public:
    static int some_value; // members used externally and internally

    Foo()
    {
        // Lots of stuff goes on in here
        // Therefore it's not a simply member initialization
        // But for this example, this should suffice
        some_value = 10;
        Foo::bar();
    }

    static void bar() { ++some_value; } // some library function

    // no destructor needed because we didn't allocate anything

private:
    // restrict copy/assignment
    Foo(const Foo&);
    void operator=(const Foo&);
};
int Foo::some_value = 0; // since some_value is static, we need this
} // library namespace
static library::Foo Foo;
} // my_project namespace

使用 Foo 将类似于此,例如:

Using Foo would be similar to this, as an example:

#include "Foo.h"
using namespace my_project;
int main()
{
    int i = Foo.some_value;
    Foo.bar();
    int j = Foo.some_value;
    return 0;
}

当然,这个例子非常简化,这种方法对我有四个好处:

Of course, this example is very simplified, but it gets the point across. This method has four advantages to me:


  1. 库的用户不需要担心初始化。他们不需要在它们的 main()内调用 Foo :: init(); code> my_project :: Foo 时初始化code> library :: Foo 这是这里的主要设计约束。

  1. User of the library doesn't need to worry about initialization. They wouldn't need to call something like Foo::init(); inside their main(), because library::Foo was initialized when my_project::Foo was constructed. This is the main design constraint here. User should not be responsible for initializing the library.

我可以在其中创建各种私人功能

I can create various private functions inside the library to control its use.

如果用户选择了这个库的其他实例,无论什么原因,用户都可以创建它的其他实例。但不允许复制。默认情况下会为它们提供一个实例。这是一个要求。

The user can create other instances of this library if they choose, for whatever reason. But no copying would be allowed. One instance would be provided for them by default. This is a requirement.

我可以使用语法代替 ::

I can use the . syntax instead of ::. But that's a personal style thing.

现在问题是,这个解决方案有什么缺点吗?我觉得我正在做一些C ++并不打算做的事情,因为Visual Studio的IntelliSense保持惊吓我,认为 my_project :: Foo 没有声明。可能是因为对象和类都被称为 Foo ,即使它们在不同的命名空间中吗?

Now, the question is, are there any disadvantages to this solution? I feel like I'm doing something that C++ wasn't meant to do because Visual Studio's IntelliSense keeps freaking out on me and thinks my_project::Foo isn't declared. Could it be because both the object and the class are called Foo even though they're in different namespaces?

解决方案编译精细。我只是担心,一旦我的项目规模越大,我可能开始有名称模糊。此外,我是通过创建这个库的对象来浪费额外的内存吗?

The solution compiles fine. I'm just worried that once my project grows larger in scale, I might start having name ambiguities. Furthermore, am I wasting extra memory by creating an object of this library?

我应该坚持单例设计模式作为替代解决方案?是否有其他解决方案?

Should I simply stick to the singleton design pattern as an alternative solution? Are there any alternative solutions?

UPDATE:

,并在google上跳过各种解决方案,我偶然发现了 extern 。我不得不说我对这个关键字真的有点模糊;自从我学习C ++以来,我一直很模糊。但在调整我的代码后,我将其更改为:

After reviewing the solutions provided, and jumping around google for various solutions, I stumbled upon extern. I have to say I'm a bit fuzzy on what this keyword really does; I've been fuzzy about it ever since I learned C++. But after tweaking my code, I changed it to this:

// Foo.h
namespace my_project
{
namespace library
{
class Foo_lib
{
public:
    int some_value;
    Foo_lib() { /* initialize library */ }
    void bar() { /* do stuff */ }
private:
    // restrict copy/assignment
    Foo_lib(const Foo_lib&);
    void operator=(const Foo_lib&);
};
} // library namespace
extern library::Foo_lib Foo;
} // my_project namespace

// Foo.cpp
#include "Foo.h"
namespace my_project
{
namespace library
{
    // Foo_lib definitions
} // library namespace
library::Foo_lib Foo;
} // my_project namespace

// main.cpp
#include "Foo.h"
using namespace my_project;
int main()
{
    int i = Foo.some_value;
    Foo.bar();
    int j = Foo.some_value;
    return 0;
}

这似乎与以前完全相同的效果。但是正如我所说,由于我对extern使用仍然模糊,这也会有同样的坏副作用?

This seems to have the exact same effect as before. But as I said, since I'm still fuzzy on extern usage, would this also have the exact same bad side-effects?

推荐答案

p>此行特别是

static library::Foo Foo;

它会产生 static c $ c> Foo 。不要使用它:) Foo :: some_value 的结果将等于Foo.h可见的翻译数,它不是线程安全的

It emits a static copy of Foo in every translation. Don't use it :) The result of Foo::some_value would be equal to the number of translations the Foo.h was visible to, and it's not thread safe (which will frustrate your users).

此行将在连接时产生多个定义:

This line will result in multiple definitions when linking:

int Foo::some_value = 0;

单身人士在这里搜索@SO会产生很多原因来避免它们。

Singletons are also bad. Searching here @SO will produce a lot of reasons to avoid them.

只需创建普通对象,并向用户记录为什么在使用库时应该共享对象,在哪些情况下。

Just create normal objects, and document to your users why they should share objects when using your library, and in which scenarios.


库的用户不需要担心初始化。他们不需要调用像Foo :: init();在他们的main(),因为library :: Foo被初始化时my_project :: Foo被构造。这是这里的主要设计约束。用户不应负责初始化库。

User of the library doesn't need to worry about initialization. They wouldn't need to call something like Foo::init(); inside their main(), because library::Foo was initialized when my_project::Foo was constructed. This is the main design constraint here. User should not be responsible for initializing the library.

对象应该能够根据需要构建自己,而不会引入不可克服的二进制行李。 p>

Objects should be able to construct themselves as needed without introducing unstrippable binary baggage.


我可以在库中创建各种私有函数来控制它的使用。

I can create various private functions inside the library to control its use.

这不是您的方法所独有的。

That's not unique to your approach.


用户可以创建此库的其他实例无论什么原因。但不允许复制。默认情况下会为它们提供一个实例。这是一个要求。

The user can create other instances of this library if they choose, for whatever reason. But no copying would be allowed. One instance would be provided for them by default. This is a requirement.

然后你可以强制用户通过 Foo 作为必要的参数来创建它们依赖的类型(需要Foo)。

Then you can force your users to pass Foo as a necessary argument to create the types they depend upon (where Foo is needed).


我可以使用。语法而不是::。但这是一个个人风格的事情。

I can use the . syntax instead of ::. But that's a personal style thing.

不好。不是线程安全的,然后用户可以严重搞乱你的库的状态。私人数据最好。

Not good. Not threadsafe, and the user can then seriously mess up your library's state. Private data is best.

这篇关于命名空间vs.静态类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆