Why is it not (easily) possible to hide private members?

Asked

Viewed 173 times

4

Implementation concealment is one of the keys to good modern software engineering, and crucial in code reuse. Why then, in c++ is it not possible to hide the private data implementation? Since these members data can basically be used only by functions members 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;
}

Testing: main.cpp

 #include "private.h"

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

   ola.mostrarMsg();
}

Why it is not possible to declare the members data private (std::string mensagem) in implementation (private.cpp)? It would not be a better software engineering to leave only the public interface available and encapsulate the internal behavior of the functions - as is intended?

Observing: The private.cpp code could be done in the form (by removing the private mybro 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;
} 

this could be considered as a good engineering in C++? The data became "private" by header and not by class definition. Why it is necessary to put privates data on headers?

3 answers

1


Why then, in c++ it is not possible to hide the private data implementation?

Why it is necessary to put privates data on headers?

This is necessary due to the way C++ organizes objects in memory.

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

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

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

Why it is not possible to declare the members 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 such separation were possible ?

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

To solve problems like this, the location of a class’s member variable declaration is limited.

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

Note: The private.cpp code could be done in the form (by removing the private mybro 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 became "private" by header and not by class definition.

As noted by you and said by the user ctgPi in his answer, this code presents a semantic change with respect to the first since there is now only one instance of the variable mensagem per programme and not one per object of the type OlaMundo. Thus it is impossible to say what is a better engineering practice since each one presents a different behavior.

  • It is not impossible for different libraries to define different methods with the same name for the same class: see Extension methods of C#, for example. In addition, other languages (such as C#, via partial classes, or Python, via Monkey patching) allow you to define methods over multiple files (although the namespacing problem is the programmer’s responsibility). C++ requires class definition to be centralized in a file (and exposed to users) because references to attributes are resolved at compile time (as is done in C), not at link-edit time.

0

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

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

Perhaps in essence your question is "why is so much C++ used to date despite the deficiencies?" ; the answer is that C++ was invented in 1983; Java, for example, was not released until 1995 (and C# in 2000).

Maybe someone with more gray hair than me here on pt.SO gives you a better context, but for a long time C++ was the only language with a certain level of adoption that allowed you to write efficient code, near the machine, and that operated at a level above pure C; Google launched the Go in 2009 to tackle this niche and correct some of the C deficiencies++.

  • To say that "we use so much C++ to this day despite the deficiencies" because it was invented first is to ignore reality. Choosing a language is not a matter of finding a perfect language but rather weighing the pros and cons of each language for the task you want to perform. Data certainly has an influence but C++ offers advantages and disadvantages that when weighted show that it is still the most appropriate language for some sectors, such as AAA game development and efficient cross-platform mobile app development.

  • I never said otherwise. I worked two and a half years at Google developing C++ code for the search engine there; I forgot to list some of these advantages in my last paragraph?

0

C++ requires private members to be declared in the header because the C++ lets you allocate objects to the stack, then its size has to be known beforehand by all customers in the class. If the class size changes, even if it is due to a modification in the list of private members, all clients have to recompile their code.

Languages like Objective-C or Java only allocate objects on the stack, and on top of that solve public members dynamically, so their actual size, as well as the positions of each member within the object structure, can 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 at will. Since the header of the Publish class never changes, clients never need to recompile the code; simply 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 guidelines for large C++ projects always recommend adding a Pimpl pointer to every class, even if it is not used at first, because it is an escape for almost every modification that is necessary, without breaking the compatibility with existing customers.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.