Позже вызовите конструктор базового класса (не в списке инициализаторов) в C ++ - PullRequest
16 голосов
/ 29 сентября 2010

Я наследую класс и хочу вызвать один из его конструкторов.Тем не менее, я должен обработать некоторые вещи (которые не требуют ничего из базового класса), прежде чем вызвать его.Есть ли способ, которым я могу просто позвонить позже, вместо вызова в списке инициализатора?Я считаю, что это можно сделать в Java и C #, но я не уверен насчет C ++.

Данные, которые мне нужно передать конструктору, не могут быть переназначены позднее, поэтому я не могу простоконструктор по умолчанию и инициализировать его позже.

Ответы [ 5 ]

29 голосов
/ 29 сентября 2010

Можно ли как-нибудь позвонить позже, а не в списке инициализаторов?

Нет, вы не можете. Конструктор базового класса должен быть вызван в списке инициализатора, и он должен быть вызван первым.

На самом деле, если вы пропустите его, компилятор просто неявно добавит вызов.

Я считаю, что это можно сделать в Java и C #, но я не уверен насчет C ++.

Ни C #, ни Java не допускают этого.

Однако, что вы можете сделать, это вызвать метод в качестве аргумента вызова конструктора базового класса. Затем он обрабатывается перед конструктором:

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

private:
    static int some_function() { return 42; }
};
15 голосов
/ 29 сентября 2010

Как сказали несколько человек, отвечающих, вы не можете отложить вызов конструктора базового класса, но Конрад дал хороший ответ , который вполне может решить вашу проблему. Однако у этого есть свои недостатки (например, когда вам нужно инициализировать несколько функций значениями, вычисления которых имеют промежуточные результаты), поэтому для простоты приведем еще один способ решения проблемы фиксированного порядка инициализации, используя , используя это.

Учитывая фиксированный порядок инициализации, если у вас есть контроль над производным классом (и как еще вы пришли бы к скрипке с одним из его ctors?), Вы можете проникнуть в частную базу, чтобы он собирался инициализироваться перед другой базой, которая затем может быть инициализирована с уже рассчитанными значениями частной базы:

class my_dirty_little_secret {
  // friend class the_class;
public: 
  my_dirty_little_secret(const std::string& str)
  {
    // however that calculates x, y, and z from str I wouldn't know
  }
  int x;
  std::string y;
  float z;
};

class the_class : private my_dirty_little_secret // must be first, see ctor
                , public the_other_base_class {
  public:
    the_class(const std::string str)
      : my_dirty_little_secret(str)
      , the_other_base_class(x, y, z)
    {
    }
  // ...
};

Класс my_dirty_little_secret является частной базой, поэтому пользователи the_class не могут его использовать, все его содержимое также является частным, с явной дружбой, предоставляющей только the_class доступ к нему. Однако, поскольку он указан первым в списке базовых классов, он будет надежно создан до the_other_base_class, поэтому все, что он вычисляет, можно использовать для его инициализации.
Хороший комментарий в списке базовых классов, надеюсь, не позволит другим нарушить работу путем рефакторинга.

1 голос
/ 29 сентября 2010

ИМХО Я не думаю, что можно отложить вызов конструктора базового класса так, как вы упомянули.

0 голосов
/ 29 сентября 2010

Ого, мы все были молоды когда-то. Этот ответ не сработает, поэтому не используйте его. Содержание оставлено для исторических целей.

Если у вас есть полный контроль над базовым классом, я бы рекомендовал добавить защищенный метод для инициализации класса, сделать его виртуальным и поместить в него детали реализации вашего производного класса, прежде чем он вызовет его базовый класс:

class Base
{
public:
    Base()
    {
        Initialize();
    }
protected:
    virtual void Initialize()
    {
        //do initialization;
    }
};

class Derived : Base
{
public:

    Derived() : Base()
    {
    }
protected:
    virtual void Initialize()
    {
        //Do my initialization
        //call base
        Base::Initialize();
    }
};
0 голосов
/ 29 сентября 2010
struct base{
   base(int x){}
};

struct derived : base{
   derived(int x) : base(x){}
};

Именно так конструкторы базового класса вызываются в C ++ из списка инициализации производного класса.

...