Por que precisamos colocar membros privados em cabeçalhos?

62

Variáveis ​​privadas são uma maneira de ocultar detalhes de complexidade e implementação para o usuário de uma classe. Este é um recurso bastante interessante. Mas eu não entendo porque no c ++ precisamos colocá-los no cabeçalho de uma classe. Vejo duas desvantagens irritantes para isso:

  • Desordena o cabeçalho do usuário
  • Força a recompilação de todas as bibliotecas clientes sempre que os internos são modificados

Existe uma razão conceitual por trás desse requisito? É apenas para facilitar o trabalho do compilador?

Simon Bergot
fonte
você pode declarar uma estrutura vazia no cabeçalho, mas então você só pode usar ponteiros para tal struct quando você usá-lo (e você não pode alocar um)
catraca aberração
3
@ratchetfreak: Não, vazio ( struct foo{};) não é permitido, mas declarações avançadas ( struct foo;) são.
MSalters
@MSalters é isso que eu quis dizer
catraca aberração
11
Deixe-me acrescentar uma desvantagem: * Escrever cabeçalhos de funções privadas no arquivo .h é uma enorme perda de tempo. (esquecendo as aulas de amigos por um momento)
Jonny

Respostas:

68

Isso ocorre porque o compilador C ++ deve saber o tamanho real da classe para alocar a quantidade certa de memória na instanciação. E o tamanho inclui todos os membros, também privados.

Uma maneira de evitar isso é usar o idioma Pimpl , explicado por Herb Sutter em sua série Guru da Semana # 24 e # 28 .

Atualizar

De fato, isso (ou mais geralmente, a ( #includes) distinção ( ões) do cabeçalho / arquivo de origem é um grande obstáculo no C ++, herdado de C. Na época em que o C ++ C foi criado, ainda não havia experiência com o desenvolvimento de software em larga escala. começa a causar problemas reais. As lições aprendidas desde então foram ouvidas pelos designers de linguagens mais recentes, mas o C ++ está vinculado a requisitos de compatibilidade com versões anteriores, tornando muito difícil abordar uma questão tão fundamental na linguagem.

Péter Török
fonte
Esse tipo de informação não está apenas contido na biblioteca de classes? É usado para vincular?
#
@ Simon, o que você quer dizer com "biblioteca de classes"?
Péter Török
Quero dizer a coleção de arquivos objeto que contém a definição e métodos de classe
Simon Bergot
7
Quando o C ++ foi criado, a AT & T / Bell Labs (empregadora da Stroustrups na época) certamente possuía experiência no desenvolvimento de C em larga escala. Seu software de troca de telefone 5ESS era, na época, provavelmente o maior programa C individual do mundo. As primeiras idéias sobre OO já são visíveis nessa base de código, e o Cfront imitou essas técnicas. No entanto, a noção de privateé mais moderna.
MSalters
11
Em C, você simplesmente colocaria o alocador em uma função de biblioteca; o cliente não seria capaz de alocar essa estrutura. Isso aumenta um pouco a sobrecarga, mas torna a migração do código entre as versões trivial, por isso geralmente vale a pena. No entanto, ele tende a levar a um estilo de código muito diferente daquele observado no C ++.
Donal Fellows
15

A definição da classe precisa ser suficiente para o compilador produzir um layout idêntico na memória, sempre que você tiver usado um objeto da classe. Por exemplo, considerando algo como:

class X { 
    int a;
public:
    int b;
};

O compilador normalmente terá ano deslocamento 0 e bno deslocamento 4. Se o compilador viu isso como justo:

class X { 
public:
    int b;
};

Ele "pensaria" que bdeveria estar no deslocamento 0 em vez do deslocamento 4. Quando o código usando essa definição atribuída a b, o código usando a primeira definição seria amodificado e vice-versa.

A maneira usual de minimizar os efeitos de fazer alterações nas partes privadas da classe é geralmente chamada de idioma pimpl (sobre o qual tenho certeza que o Google pode fornecer uma grande quantidade de informações).

Jerry Coffin
fonte
11
Estou perguntando sobre uma decisão de design. É claro que você precisaria colocar a declaração de membro particular em algum lugar para o idioma funcionar. Mas por que deveria estar no cabeçalho e não em um local mais privado?
Simon Bergot
7
@ Simon: O cabeçalho é tudo o que o compilador vê para dizer como é a classe / estrutura. Houve discussões sobre a adição de algo como módulos ao C ++, o que ocultaria esse tipo de dados um pouco mais, mas até agora não foi aprovado (embora também não tenha sido totalmente descartado).
21712 Jerry Coffin
3
Ainda assim, uma regra trivial seria alocar esses membros privados "definidos por .cpp" por último. Isso significa que as compensações dos membros públicos e privados "normais" não dependeriam deles. Na IMO, o verdadeiro motivo é que você não pode herdar dessa classe, pois a parte derivada precisa seguir até mesmo os membros privados.
MSalters
3

Provavelmente, existem várias razões. Embora os membros privados não possam ser acessados ​​pela maioria das outras classes, eles ainda podem ser acessados ​​pelas classes de amigos. Portanto, pelo menos nesse caso, eles podem ser necessários no cabeçalho, para que a classe amiga veja que eles existem.

A recompilação de arquivos dependentes pode depender da sua estrutura de inclusão. A inclusão dos arquivos .h em um arquivo .cpp em vez de outro cabeçalho pode, em alguns casos, impedir longas cadeias de recompilações.

thorsten müller
fonte