在C ++类中,我应该将私有函数和变量放在类头定义的私有部分中,还是放在类源文件中?为什么?
例如:
// Header
class MyClass {
public:
void doSomething();
private:
int a = 0;
}
// Source
void MyClass::doSomething()
{
// Do something with `a`
}
或
// Header
class MyClass {
public:
void doSomething();
}
// Source
int a = 0;
void MyClass::doSomething()
{
// Do something with `a`
}
我一直认为,编程时最好尽量减少函数/变量的范围。那么不应该将var a
的范围限制在源文件的范围内吗?
答案 0 :(得分:2)
它们并不等同。第一个例子
// Header
class MyClass {
public:
void doSomething();
private:
int a = 0;
}
// Source
void MyClass::doSomething()
{
++a;
cout << a << endl;
}
int main()
{
MyClass x, y;
x.doSomething();
y.doSomething()
}
输出
1
1
第二个例子
// Header
class MyClass {
public:
void doSomething();
}
int a = 0;
// Source
void MyClass::doSomething()
{
++a;
cout << a << endl;
}
int main()
{
MyClass x, y;
x.doSomething();
y.doSomething()
}
输出
1
2
在第一个示例中,a
是一个类变量,因此x
和y
拥有自己的a
副本。在第二个示例中,只有一个全局变量a
,因此输出不同。
答案 1 :(得分:0)
你可以使用pimpl习语......或者,你可以使用pimpl习语的这个变体,其中实现的内存直接由接口类提供:
在档案MyClass.hpp
中:
class MyClass{
private:
std::byte buffer[N];
public:
MyClass();
void public_method();
~MyClass();
};
在课程MyClass.cpp
中:
#include "MyClass.hpp"
namespace{
struct MyClassImpl{
private:
int val=0;
public:
void secret_method(){/*...*/}
};
inline const MyClassImpl&
get(const std::byte* buffer){
//In theory, in C++17 you should use std::launder here to be standard compliant
//in practice, compilers generate the expected code without std::launder
//and with std::launder they generate horrible and inefficient code!
return *reinterpret_cast<const MyClassImpl*>(buffer);
}
inline MyClassImpl&
get(const std::byte* buffer){
//idem here to be c++17 standard compliant launder is necessary
//in practice, it would be a mistake.
return *reinterpret_cast<MyClassImpl*>(buffer);
}
}
MyClass::MyClass(){
new(buffer) MyClassImpl{};
}
MyClass::~MyClass(){
get(buffer).~MyClassImpl();
}
void
MyClass::public_method(){
/*....*/
get(buffer).secret_method();
/*....*/
}
与传统的pimpl成语相比:
优点:内存访问量减少,堆上没有内存分配,效率更高
缺点:容易出错,执行的大小&#34;泄漏&#34;在界面中。