Mahi
Mahi

Reputation: 21893

Avoid copying all constructors in subclasses

So a base class has multiple constructors:

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

And I'm subclassing this class multiple times:

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
};

As you see, I have to repeat these three constructors for every subclass. Is there a way to avoid this, since the constructors usually don't do anything special? Sometimes I need some class specific initialization though, so it's not always viable to just straight out copy everything.

Upvotes: 21

Views: 3613

Answers (3)

Walter
Walter

Reputation: 45424

If you can just 'inherit' the constructor, i.e. have one with exactly the same arguments, simply use using as explained in the other answers. However, if your derived class's constructor has additional arguments and/or requires some class specific initialization, you may use a variadic template.

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
};

Upvotes: 7

songyuanyao
songyuanyao

Reputation: 172914

You can accomplish this by inheriting constructors (since C++11).

If the using-declaration refers to a constructor of a direct base of the class being defined (e.g. using Base::Base;), all constructors of that base (ignoring member access) are made visible to overload resolution when initializing the derived class.

e.g.

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

        // My subclass specific code
};

If the inherited constructors is used to initialize a Sub, the sf::Sprite subobject is initialized using the inherited constructor, and all other members of Sub are initialized as if by the defaulted default constructor.

If there're some special cases need to be processed, you still can define constructor(s) in Sub, the inherited constructor with the same signature will be hidden.

As with using-declarations for any other non-static member functions, if an inherited constructor matches the signature of one of the constructors of Derived, it is hidden from lookup by the version found in Derived.

Upvotes: 36

Sebastian Stern
Sebastian Stern

Reputation: 642

You can use the using keyword to inherit the constructor of your base class, excluding the special ones (default, copy, move). To shorten your default constructor simply use = default. If you want class specific initialization you can simply write the constructor again, just as you do now.

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

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

        // My subclass specific code
};

Upvotes: 15

Related Questions