C++头文件中声明私有成员变量与在cpp文件中声明静态变量的区别

6

我有一个变量,我希望在cpp文件中声明它,而不是头文件。它应该只能被该类的对象访问。这个变量应该为该类的每个对象分别拥有一份独立的副本。继承不是必需的。

通常,我会在类定义中声明它。

A.h:

class A {
    private:
        int number;
}

但是,我可以这样做吗?
B.h:
class B {
    private:
        // nothing
}

B.cpp:

static int number;

1
你最初建议的正常方法(将其声明为非静态“private”成员)有什么问题? - iammilind
在.cpp文件中声明的一个原因是,如果所有的私有成员都是结构体,我需要在头文件中声明所有的结构体,这会很混乱。但除此之外,没有问题。我也想知道这两种方法是否相同。 - Coder
6个回答

14

如果您的目标是隐藏实现细节,让客户端只能看到您的头文件(可能是为了保密,或者避免依赖库内部实现细节),那么您寻找的设计模式是 pimpl 模式(“指向实现的指针”)。

myclass.h:

class MyClassImpl;

class MyClass
{
    public:
        MyClass();
        ~MyClass();
        int someFunc();

    private:
        MyClassImpl * pimpl;
}

myclass.cpp:

class MyClassImpl
{
    public:
        MyClassImpl();
        int someFunc();

    private:
        // whatever members you actually need
}

MyClass::MyClass()
{
    pimpl = new MyClassImpl();
}

MyClass::~MyClass()
{
    delete pimpl;
}

int MyClass::someFunc()
{
    return pimpl->someFunc();
}

// go on implementing MyClassImpl as you would have implemented MyClass

注意: 此示例代码没有正确的复制语义。您可能希望使用智能指针,或实现适当的复制构造函数/赋值运算符。


是的,就是这样,我想我会使用类似这样的东西。谢谢! - Coder

13
不,如果采用第二种方法,你会把它变成一个静态变量,这意味着对于该类的每个对象,你都不会有一个不同的副本(它们将共享该变量)。
无论哪种方式,如果它只应该被该类访问,它应该放在类声明中,而不应该是全局变量。通过将其设置为静态全局变量,你限制了它仅在文件作用域内访问,而不是限制在类内部。作为良好的编程实践,请尽可能少使用全局变量。

+1,如果提到类声明中的静态和自由函数作用域修饰符中的静态之间的区别。 - Pedro d'Aquino

7

使用私有实现模式,可以在cpp文件中隐藏数据成员。

该模式可以使代码更加安全并且易于维护。
//a.hpp
struct AData;

class A
{
public:
  A();
private:
  AData* data_members;
};

//a.cpp
struct AData
{
   int number;
};

A::A(): data_members(new AData()) {}

不确定只使用一个整数是否值得。但这可以用于减少编译时间:您可以随意修改A的“数据成员”和实现,而无需重新编译包括a.hpp在内的文件。

此外,最好使用适当的智能指针而不是简单指针(具有适当的复制行为并且可以声明为不完整类型)。


1
This variable should have a separate copy for every object of that class. 

保持静态不会让你实现这个目标。它将成为所有实例共享的一个副本。

如果你想让每个对象都有自己的number副本,那么你就需要将它作为你类的成员。


0
如果您想为类的每个对象创建单独的副本,您需要在头文件中声明它,或者使用某种静态映射来存储对象值和该对象对应值之间的关系,并由对象构造函数进行初始化。

0
如果您想让一个变量与类对象相关联,它必须在类内部声明。所有的对象数据都应该在类内部。 这就是所谓的封装。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接