Pergunta

O que é o C ++ regras para chamar o construtor da superclasse de uma subclasse?

Por exemplo, eu sei em Java, você deve fazê-lo como a primeira linha do construtor de subclasse (e se você não fizer isso, uma chamada implícita para um construtor de super-no-arg é assumido - o que lhe dá um erro de compilação se o que está faltando).

Foi útil?

Solução

construtores classe base são automaticamente chamado para você, se eles não têm nenhum argumento. Se você quiser chamar um construtor de superclasse com um argumento, você deve usar lista de inicialização do construtor das subclasse. Ao contrário de Java, suporta C ++ herança múltipla (para melhor ou pior), para a classe base deve ser referido pelo nome, ao invés de "super ()".

class SuperClass
{
    public:

        SuperClass(int foo)
        {
            // do something with foo
        }
};

class SubClass : public SuperClass
{
    public:

        SubClass(int foo, int bar)
        : SuperClass(foo)    // Call the superclass constructor in the subclass' initialization list.
        {
            // do something with bar
        }
};

Mais informações sobre lista de inicialização do construtor aqui e aqui .

Outras dicas

Em C ++, os construtores sem argumentos para todas as superclasses e variáveis ??de membro são chamados para você, antes de entrar em seu construtor. Se você quer passar-lhes argumentos, há uma sintaxe separada para este chamado de "encadeamento construtor", que tem esta aparência:

class Sub : public Base
{
  Sub(int x, int y)
  : Base(x), member(y)
  {
  }
  Type member;
};

Se alguma coisa correr neste momento joga, as bases / membros que haviam completado anteriormente construção têm seus destruidores chamados e a exceção é relançada para o chamador. Se você quiser capturar exceções durante encadeamento, você deve usar um bloco de função tentativa:

class Sub : public Base
{
  Sub(int x, int y)
  try : Base(x), member(y)
  {
    // function body goes here
  } catch(const ExceptionType &e) {
    throw kaboom();
  }
  Type member;
};

Nesta forma, nota que o bloco try é o corpo da função, em vez de ser dentro do corpo da função; isso permite excepções de captura lançadas por inicializações membro e classe base implícitos ou explícitos, bem como durante o corpo da função. No entanto, se um bloco de função captura não lançar uma exceção diferente, o tempo de execução vai relançar o erro original; exceções durante a inicialização não pode ser ignorado.

Em C ++, há um conceito de lista de inicialização do construtor, que é onde você pode e deve chamar o construtor da classe base e onde você também deve inicializar os membros de dados. A lista de inicialização vem depois da assinatura de construtor após uma cólon, e antes do corpo do construtor. Vamos dizer que nós temos uma classe A:


class A : public B
{
public:
  A(int a, int b, int c);
private:
  int b_, c_;
};

Então, supondo que B tem um construtor que leva um int, o construtor de A pode ser parecido com isto:


A::A(int a, int b, int c) 
  : B(a), b_(b), c_(c) // initialization list
{
  // do something
}

Como você pode ver, o construtor da classe base é chamado na lista de inicialização. Inicializar os membros de dados na lista de inicialização, por sinal, é preferível atribuir os valores para b_, e c_ dentro do corpo do construtor, porque você está economizando o custo extra de trabalho.

Tenha em mente, que os membros de dados são sempre inicializados na ordem em que eles são declarados na definição da classe, independentemente de sua ordem na lista de inicialização. Para evitar bugs estranhos, que podem surgir se os seus membros de dados dependem uns dos outros, você deve sempre se certificar de que a ordem dos membros é o mesmo na lista de inicialização e a definição de classe. Pela mesma razão, o construtor da classe base deve ser o primeiro item na lista de inicialização. Se você omiti-lo completamente, então o construtor padrão para a classe base será chamado automaticamente. Nesse caso, se a classe base não tem um construtor padrão, você receberá um erro do compilador.

Todo mundo mencionou uma chamada do construtor através de uma lista de inicialização, mas ninguém disse que o construtor de uma classe pai pode ser chamado explicitamente do corpo do construtor do membro do derivado. Veja a pergunta Chamar um construtor da classe base de uma subclasse corpo do construtor , por exemplo. O ponto é que se você usar uma chamada explícita para uma classe pai ou construtor da classe super no corpo de uma classe derivada, isso é realmente apenas criar uma instância da classe pai e não é invocando o construtor da classe pai no objeto derivado . A única maneira de chamar uma classe pai ou construtor da classe super-on objeto uma classe derivada é através da lista de inicialização e não no corpo do construtor da classe derivada. Talvez por isso, não deve ser chamado de uma "chamada de construtor da superclasse". Eu coloquei esta resposta aqui porque alguém pode ficar confuso (como eu fiz).

A única maneira de passar valores para um construtor pai é através de uma lista de inicialização. A lista initilization é implementado com um:. E, em seguida, uma lista de classes e os valores a serem passados ??para esse construtor aulas

Class2::Class2(string id) : Class1(id) {
....
}

Lembre-se também que, se você tem um construtor que leva sem parâmetros na classe pai, ele será chamado automaticamente antes de o construtor criança execução.

Se você tem um construtor sem argumentos que serão chamados antes do construtor da classe derivada é executado.

Se você quiser chamar um base-construtor com argumentos que você tem que escrever explicitamente que no construtor derivado assim:

class base
{
  public:
  base (int arg)
  {
  }
};

class derived : public base
{
  public:
  derived () : base (number)
  {
  }
};

Você não pode construir uma classe derivada sem chamar o construtor pais em C ++. Que ou acontece automaticamente se é um não-arg C'tor, isso acontece se você chamar o construtor derivado diretamente como mostrado acima ou o seu código não irá compilar.

Se você tem parâmetros padrão em seu construtor base da classe base será chamado automaticamente.

using namespace std;

class Base
{
    public:
    Base(int a=1) : _a(a) {}

    protected:
    int _a;
};

class Derived : public Base
{
  public:
  Derived() {}

  void printit() { cout << _a << endl; }
};

int main()
{
   Derived d;
   d.printit();
   return 0;
}

A saída é: 1

CDerived::CDerived()
: CBase(...), iCount(0)  //this is the initialisation list. You can initialise member variables here too. (e.g. iCount := 0)
    {
    //construct body
    }

Ninguém mencionou a seqüência de chamadas do construtor quando uma classe deriva de várias classes. A sequência é tal como mencionado, enquanto derivando as classes.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top