开发者

Is this a valid workaround to the constructor issue with mixins?

As I understand there is a problem with mixins where, if you want to use something other than a no-arg constructor, the objects you use your mixin on will either have to have a common constructor signature or you have to use initializer methods in the classes you want to use the mixin with.

This seems to be kind of a workaround, though I'm not sure if there are situations in which it would fail. It makes the mixin work more like a decorator, but it removes the need for the common interface that the decorators inherit from. I guess another problem is that the syntax might get clunky?

Just want to know if there is anything horribly dangerous about this. I also would like to know if I, being a not so smart programmer, have misunderstood this problem with mixins.

Edit: this appears to be a better formulation.

class Base
{
protected:
    std::string name;
public:
    Base()
    {
        name = "no arg constructor";
    }
    Base(std::string n)
    {
        name = n;
    }

    virtual void doSomething()
    {
        cout << name << "\n";
    }
};

class Derived : public Base
{
private:
    int x;
public:

    Derived(std::string n, int i) : Base(n)
    {
        x = i;
    }

    void doSomething()
    {
        cout << "x = " << x << "\t";
        Base::doSomething();
    }
};

template <class T>
class Decorator : public T
{
public:
    Decorator(const T& initializer) : T(initializer)
    {
        //*static_cast< T* >(this) = *initializer;
        //delete initializer;
    }
};

void method(Base& b)
{
    b.doSomething();
}

int main()
{
    Base b;
    Decorator<Base> d1(b);
    Decorator<Base> d2(Base("decorated"));
    Decorator<Derived> d3(Derived("derived", 777));

    method(d1);
    method(d开发者_JS百科2);
    method(d3);

    return 0;
}

no arg constructor

decorated

x = 777 derived


  1. You're leaking memory if an exception is thrown during construction,
  2. The base class must have a default constructor to be be constructed first and then assigned.

Better do:

Decorator(const T& initializer) : T(initializer)
{
}

and use:

Decorator<Base> d1((Base()));
Decorator<Base> d2(Base("decorated"));
Decorator<Derived> d3(Derived("derived",777));

Also in C++0x you can forward perfectly any number of arguments from Decorator's constructor to the base constructor, effectively making the usage as clean as usual:

Decorator<Base> d1;
Decorator<Base> d2("decorated");
Decorator<Derived> d3("derived",777);


This is the reason why C++0x included the ability to forward, safely, an arbitrary number of elements:

template <typename T>
struct Decorator: T
{
  template <typename... Args>
  Decorator(Args&&... args): T(args...) {}
};

Which forwards the arguments cleanly. Check it out on ideone!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜