Se o construtor não for explicit, ele automaticamente será chamado. Por exemplo, você poderia fazer isso aqui:
State x = “Novo estado”;
E o C++ automaticamente converteria para isso aqui:
State x = new State(novoEstado);
Já que você tem um construtor que aceita um std::string. O mesmo vale pra métodos que aceitem um State como parâmetro.
Como isso aí gera um código sujeito a erros, você só deve declarar o construtor sem explicit caso sua classe efetivamente represente algo que deva ser implicitamente convertido. Por exemplo, a classe BigDecimal do Java poderia se beneficiar desse recurso.
[quote=Schuenemann]Sobre a lista de inicialização, qual a explicação para essa (aparente) loucura?
Com a atribuição com =, ele primeiro tentou instanciar o atributo de Helper para depois atribuir ao parâmetro? Por quê?
E se não fosse uma simples atribuição? Se tivesse uma validação antes, por exemplo?[/quote]
Por que é assim que o C++ funciona. Antes de começar o construtor, ele faz a inicialização padrão de todos os atributos da classe. Quem comanda essa inicialização padrão é a lista de inicialização.
O java, no fundo, faz exatamente a mesma coisa. Tanto que quando você roda o construtor, todos os atributos valem 0, e todas as referências valem null, ou seja, uma inicialização padrão foi executada.
A diferença é que a lista de inicialização te dá a oportunidade de alterar essa inicialização padrão, poupando alguns milisegundos de processamento.
O Java não suporta o conceito de referência, como o C++, e não suporta também o conceito de objetos por valor. Nesses casos, você tem que tomar especial cuidado, pois na inicialização padrão o C++ irá tentar criar um objeto novo, usando o construtor padrão. A lista de inicialização se torna importante, pois a construção de um objeto, diferente da de um tipo primitivo, pode ser custosa.
Se você precisar validar valores de atributos, faça isso dentro do corpo do construtor. A única diferença é que os atributos não irão valer 0, pois os valores já estarão atribuídos, graças a lista de inicialização. Lembre-se que referências em C++ obrigatoriamente devem conter um valor de objeto, pois não podem ser nulas. No caso de ponteiros, é uma prática comum inicializa-los com null na lista de inicialização, fazer as validações de atributos no construtor, para tentar evitar dar o new, como o java faz.