How can I fake constructor inheritance in C++03?

纵饮孤独 提交于 2019-12-24 14:48:21

问题


As far as I know, you cannot inherit constructors in C++. But there are situations, where it might be required that it looks like you can instantiate inherited classes the same way you instantiate their base:

struct Base {
  int i;
  int const j;
  Base(int i, int j) : i(i), j(j) {}
};

// option 1)
struct Derived1 : Base {
  Derived1(int i, int j) : Base(i,j) {}
};
Base* baseFactory() {
  return new Derived1(42,47);
}

// option 2)
struct Derived2 : Base {
};
Base* baseFactory() {
  Base* b = new Derived2();
  b->i = 42;
  b->j = 47; // broken!
  // alternative could be to implement Base::operator=
  return b;
}

Note that the derived classes could be default constructed if it weren't for their base class(es).

Option 1 is what is usually done, I think, but you are typing code without expressing anything new. Option 2 breaks const correctness (and prevents you from using references as members) because everything must be assignable.

Is there a nice way around this?

Edit: C++11 is great, but unfortunately I need a C++03 solution.


回答1:


There is an alternative approach:

// option 3)
struct Derived3 : Base {
  Derived3(const Base &b) : Base(b) {}
};
Base* baseFactory3() {
    return new Derived3(Base(42,47));
}

This may not be a good idea if constructing a full Base object is expensive or requires external resources. In that case you could create a light-weight object that carries constructor arguments for Base, so that instead of multiple Base constructors you have multiple BaseArguments constructors, and one Base constructor that takes in BaseArguments. However I don't think many people would consider that good style in most circumstances.




回答2:


Option 1 is the idiomatic way in C++03, it does require more typing, but that is how the language is. Option 2 is not even close to equivalent, you would not be able to initialize Derived2 as Base does not have a default constructor, and the definition of the implicitly declared default constructor for Derived2 needs it.

But beyond the technical difficulty in the language you are trading construction for two-phase construction which is never a good idea, and at the same time forcing your use of Derived2 to dynamically allocated objects.




回答3:


C++11 supports inherited constructors.

http://en.wikipedia.org/wiki/C%2B%2B11

However not all compilers that supports now a subset of C++11 supports all functionalities.

Microsoft visual C++ 2010 supports several new C++0x features but not inherited constructors, here is a list: http://blogs.msdn.com/b/vcblog/archive/2010/04/06/c-0x-core-language-features-in-vc10-the-table.aspx

GCC supports more new features but not the inherited constructors. See http://gcc.gnu.org/projects/cxx0x.html

To enable GCC to compile with C++0x features you need to add -std=c++0x or -std=gnu++0x compilation parameter. Visual C++ 2010 have these enabled by default.

You just need to wait :)

There are not clean solutions for previous version of the standard, for this reason it was introduced in C++11, because it was not possible to do with previous versions. So, the only thing you can do, is to copy your constructors and call base constructor.




回答4:


Here' a variation on the Builder Pattern that I always thought it could be useful, but I never actually got a chance to use it; I guess you could call it the Constructor Pattern. :P

It also offers some other advantages, like not having to specify arguments in a certain order: you only specify what you are interested in and in whatever order you want.

I still think this is justified only if your class has lots of constructors with different parameters. Otherwise, it's just an annoyance.

class Person
{
  public:
    class Constructor;
};

class Person::Constructor
{
  public:
    Constructor& name(const std::string&);
    Constructor& age(int);
    Person* make();
};

Person* pers = Person::Constructor()
    .name("Bob Marley").make();


class Employee : public Person
{
  public:
    class Constructor;
};

class Employee::Constructor : public Person::Constructor
{
  public:
    Constructor& salary(double);
    Employee* make();
};

Employee* emp = Employee::Constructor()
    .name("Emilly Smith").age(23).make();

But again, this is justifiable only if your class has lots of constructors with lots of parameters and you want to avoid having to write multiple overloads to those; otherwise, this just adds too much complexity without any real benefit.

I mentioned I don't like han's proposed solution. This is because (1) you are moving the need to (re)declare a number of constructors in the child class to the need to place the same number of functions inside a factory class; (2) it is hacky and the intent is not explicit; and (3) you could view this as a violation of dependency injection.



来源:https://stackoverflow.com/questions/7938204/how-can-i-fake-constructor-inheritance-in-c03

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!