Подтвердить что ты не робот

Избегайте копирования всех конструкторов в подклассах

Таким образом, базовый класс имеет несколько конструкторов:

sf::Sprite()
sf::Sprite(const Texture& texture)
sf::Sprite(const Texture& texture, const IntRect& rectangle)

И я подклассифицирую этот класс несколько раз:

class Sub : public sf::Sprite {
    public:
        Sub() : sf::Sprite() {};
        Sub(const Texture& texture) : sf::Sprite(texture) {};
        Sub(const Texture& texture, const IntRect& rectangle) : sf::Sprite(texture, rectangle) {};

        // My subclass specific code
};

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

4b9b3361

Ответ 1

Вы можете выполнить это с помощью наследующих конструкторов (начиная с С++ 11).

Если декларация using ссылается на конструктор прямой базы определяемого класса (например, using Base::Base;), все конструкторы этой базы (игнорируя доступ к членству) становятся видимыми для разрешения перегрузки при инициализации производного класса.

например.

class Sub : public sf::Sprite {
    public:
        using sf::Sprite::Sprite;

        // My subclass specific code
};

Если унаследованные конструкторы используются для инициализации Sub, подобъект sf::Sprite инициализируется с помощью наследуемого конструктора, а все остальные члены Sub инициализируются, как если бы по умолчанию используемый конструктор по умолчанию.

Если необходимо обработать некоторые особые случаи, вы все равно можете определить конструктор в Sub, унаследованный конструктор с той же сигнатурой будет скрыт.

Как и при использовании-деклараций для любых других нестатических функций-членов, если унаследованный конструктор соответствует сигнатуре одного из конструкторов Derived, он скрыт от поиска версией, найденной в Derived.

Ответ 2

Вы можете использовать ключевое слово using для наследования конструктора базового класса, за исключением специальных (по умолчанию, копирования, перемещения). Чтобы сократить конструктор по умолчанию, просто используйте = default. Если вы хотите инициализацию, специфичную для класса, вы можете просто написать конструктор снова, как и сейчас.

class Sub : public sf::Sprite {
    public:
        Sub() = default;
        using sf::Sprite::Sprite;

        Sub(const Texture& texture) 
        {
           // your custom code.
        };

        // My subclass specific code
};

Ответ 3

Если вы можете просто "наследовать" конструктор, т.е. иметь один с точно такими же аргументами, просто используйте using, как объяснено в других ответах. Однако, если ваш конструктор класса derived имеет дополнительные аргументы и/или требует некоторой инициализации определенного класса, вы можете использовать вариационный шаблон.

struct base
{
  base(int);
  base(std::string const&);
  base(some_type const&);
  base(std::string const&, some_type const&);
  /* ... */
};

struct derived : base
{
  template<typename...Args>
  derived(some_other_type const&x, Args&&...args)
  : base(std::forward<Args>(args)...)
  , private_datum(x)
  {
    construction_details();          // class-specific initialisation
  }
private:
  some_other_type private_datum;
  void construction_details();       // implemented in source code
};