Why can not (easily) hide private members?

4
Concealing implementation is one of the keys to good modern software engineering, and crucial in code reuse. Why then in c ++ it is not possible to hide the private data implementation? Since this member data can basically only be used by member functions of the class (or friends). Given the usual code below:

private.h

#ifndef PRIVATE_H
#define PRIVATE_H

#include <string>

class OlaMundo {

public: 
   OlaMundo(std::string);

   void mostrarMsg();

private:
   std::string mensagem;
};

#endif

private.cpp

#include "private.h"
#include <iostream>

OlaMundo::OlaMundo(std::string msgArg) {

   mensagem = msgArg;
}

void OlaMundo::mostrarMsg() {

   std::cout << "Olá, " << mensagem << "!" << std::endl;
}

Test: main.cpp

 #include "private.h"

 int main()
{
   OlaMundo ola("Rafael");

   ola.mostrarMsg();
}

Why can not declare private member data ( std::string mensagem ) in implementation (private.cpp)? Would not it be better software engineering to leave only the public interface available and encapsulate the internal behavior of functions - how do you intend it?

Note: The private.cpp code could be done the way (by removing the private key from the corresponding header:

#include "private.h"
#include <iostream>

std::string mensagem;

OlaMundo::OlaMundo(std::string msgArg) {

   mensagem = msgArg;
}

void OlaMundo::mostrarMsg() {

    std::cout << "Olá, " << mensagem << "!" << std::endl;
} 

Could this be considered as good engineering in C ++? The data has become "private" by header and not by class definition. Why is it necessary for privates data in the headers?

    
asked by anonymous 10.06.2015 / 03:06

3 answers

1
  

Why then in c ++ can not hide the private data implementation?

     

Why is it necessary for the privates data in the headers?

This is necessary because of the way C ++ organizes objects in memory.

When you declare a variable in C ++, the compiler needs to know how much space it will take to store that information so it can reserve space on the stack.

So, to be able to declare variables of the type of a class it is necessary to be able to calculate its size and consequently that all its members are visible at that point of the code.

Note that a variable of type OlaMundo * is not of type of class (the type is pointer to object of type OlaMundo ), so the compiler only needs to know the size that a pointer occupies when this variable is being declared, since the size of pointers to data is independent of the data type, so it is not necessary for the class definition to be visible, just its declaration.

  

Why can not I declare the member data private ( std::string mensagem ) in the implementation ( private.cpp )?

In addition to the problem already mentioned, another problem would be how to limit who can insert members into the class if this separation is possible?

What would happen, for example, if the file private1.cpp added a member variable std::string mensagem to class OlaMundo and another file named private2.cpp added a member variable char * mensagem to the same class? What if one of these files was compiled into a library?

To solve problems like this, limit the location of the declaration of member variables of a class.

Armed with all this information we can understand the current state of C ++: when defining a class / structure all its members, including private members, must be specified.

  

Note: The private.cpp code could be done the way (by removing the private key from the corresponding header:

#include "private.h"
#include <iostream>

std::string mensagem;

OlaMundo::OlaMundo(std::string msgArg) {
    mensagem = msgArg;
}

void OlaMundo::mostrarMsg() {
    std::cout << "Olá, " << mensagem << "!" << std::endl;
} 
     

Could this be considered as good engineering in C ++? The data has become "private" by header and not by class definition.

As noted by you and said by the user ctgPi in your answer, this code presents a semantic change with relative to the first since there is now only one instance of the variable mensagem per program and not one per object of type OlaMundo . So it is impossible to say which is a better engineering practice since each one behaves differently.

    
11.06.2015 / 21:28
0

The first and second versions are not equivalent - they would be closer if mensagem was static private .

But yes, this is a known problem with C ++ , which is aggravated by the fact of changes in the internal structure of the class force recompilation of everything the code that references that class (and, to make matters worse, C ++ is not exactly a fast build language).

Maybe deep down your question is "why is it used so much C ++ even today despite the shortcomings?"; the answer is that C ++ was invented as early as 1983; Java, for example, was only released in 1995 (and C # in 2000).

Maybe someone with more gray hair than I do here in pt.SO give you better this context, but for a long time C ++ was the only language with a certain level of adoption, allowing write efficient code, close to the machine, and which operates at a level above pure C; Google launched Go in 2009 to tackle this niche and correct some of the C ++ deficiencies.

    
10.06.2015 / 03:37
0

C ++ requires private members to be declared in the header because C ++ allows allocating objects in the stack , so their size must be known in advance by all clients in the class. If the class size changes, even if it is because of a change in the private member list, all clients have to recompile their code.

Languages such as Objective-C or Java only allocate objects on the stack, and override public members dynamically, so their actual size, as well as the positions of each member within the object's structure, may be hidden in the implementation .

In fact it is possible to hide the private part of a C ++ class using the "Pimpl language":

// cabeçalho público, fornecido aos clientes

class Publica_pimpl;

class Publica {
   public:
       ...
   private:
       Publica_pimpl* p;
};

// cabeçalho privado, que os clientes não precisam receber

class Publica_pimpl {
   ... seus membros e métodos privados aqui ...
};

By isolating the private part of the class into a separate class, you can modify it privately. Because the Public class header never changes, clients never need to recompile the code; just distribute an updated version of the compiled library (assuming the class is distributed as a library and not as a source). Any change in Publica_pimpl only affects the library itself.

The great C ++ project guidelines always recommend adding a Pimpl pointer to every class, even if it is not used at first, because it is an escape from almost any modification that is needed without breaking compatibility with existing clients.

    
04.09.2015 / 18:21