简体   繁体   中英

Do I need to define all private functions and variables in class header C++

In a C++ class, should I be placing my private functions and variables in the private section of the class header definition, or in the class source file and why?

For example:

// Header
class MyClass {
public:
    void doSomething();
private:
    int a = 0;
}

// Source
void MyClass::doSomething()
{
    // Do something with `a`
}

or

// Header
class MyClass {
public:
    void doSomething();
}

// Source
int a = 0;

void MyClass::doSomething()
{
    // Do something with `a`
}

I've always thought, when programming it's best to make the scope of a function/variable as small as possible. So shouldn't restricting the scope of the var a to the scope of the source file be best?

They are not equivalent. First example

// 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()
}

Output

1
1

Second example

// 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()
}

Output

1
2

In the first example a is a class variable so x and y have their own copy of a . In the second example there is only one global variable a so the output is different.

You could use the pimpl idiom... Alternatively, you could use this variant of the pimpl idiom, where the memory of the implementation is directly provided by the interface class:

In file MyClass.hpp :

class MyClass{
  private:
    std::byte buffer[N];
  public:
    MyClass();
    void public_method();
    ~MyClass();
  };

In class 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();
    /*....*/
    }

Compared to classical pimpl idiom:

  • Pros : less memory access, no memory allocation on the heap, more efficient

  • Cons : error prone, the size of the implementation "leak" in the interface.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM