多态性从C++中的基类返回派生的"this"

0 c++ polymorphism inheritance casting class

在C++中遇到一些多态问题.我正在尝试为初始化类创建一个相当奇怪的语法,但是当我从基类方法返回"this"时,我似乎丢失了新创建的派生类.

在下面的伪代码中,我需要让Base :: initWithPuppies()能够执行一些默认操作并返回它正在调用的派生类.

我想要这个语法:

Bar *baz = (new Bar)->initWithPuppies();
Run Code Online (Sandbox Code Playgroud)

最好使用模板,需要投射如下:

initWithPuppies<Bar *>();
Run Code Online (Sandbox Code Playgroud)

是的,我知道这是相当怪异的.但这是有原因的,"最佳实践"并不适用于这种情况.考虑这只是"假设".我知道你应该:

Bar *baz = new Bar;
baz->initWithPuppies();
Run Code Online (Sandbox Code Playgroud)

但我需要以前的语法.

伪代码:

class Base
{
    // Kittens
};

class Foo : public Base
{
  public:
    Base * initWithPuppies();
    virtual void test() = 0;
};

Base * Foo::initWithPuppies()
{
    // Call to derived works
    this->test();

    return this;
}

class Bar : public Foo
{
  public:
    void test();
};

void Bar::test()
{
    std::cout << "It Works!" << std::endl;
}

// Preferred syntax
// This gives "cannot convert from 'Base *' to 'Bar *' "
Bar *baz = (new Bar)->initWithPuppies();

baz->test();

/*------------------------------------------*/

// This gives " 'test' : is not a member of 'Base' "
Base *baz = (new Bar)->initWithPuppies();

baz->test();

/*------------------------------------------*/

// This gives "Base is not a polymorphic type"
UIBar *man = dynamic_cast<UIBar *>((new UIBar)->initWithFrame());

baz->test();
Run Code Online (Sandbox Code Playgroud)

编辑:

如果以某种方式可能有这种语法:

Bar *baz = (Bar::create())->initWithPuppies();
Run Code Online (Sandbox Code Playgroud)

那会更好,但我无法弄清楚如何在基类中创建一个没有类型转换的派生的新实例:

Bar *baz = (Bar::create<Bar *>())->initWithPuppies();
Run Code Online (Sandbox Code Playgroud)

我的答案:( 8小时内无法自己回答)

虽然Nicol Bolas是正确的,并且我说我想要使用的语法是不好的做法,如果你确实需要使用与我类似的语法(不要问......)那么你可以这样做:

class Base
{
    // Kittens
};

class Foo : public Base
{
  public:
    virtual void test() = 0;
  private:
    void _initWithPuppies();
};

void Foo::initWithPuppies()
{
    // Do shit
}

class Bar : public Foo
{
  public:
    Bar * initWithPuppies();
    void test();
};

Bar * Bar::initWithPuppies()
{
    this->_initWithPuppies();

    return this;    
}

void Bar::test()
{
    std::cout << "It Works!" << std::endl;
}


Bar *baz = (new Bar)->initWithPuppies();

baz->test();
Run Code Online (Sandbox Code Playgroud)

Nic*_*las 9

我想要这个语法:

Bar *baz = (new Bar)->initWithPuppies();
Run Code Online (Sandbox Code Playgroud)

好的,停在那儿.那不是你想要的语法.构造函数存在于C++中是有充分理由的,除非你有充分的理由绕过它们,否则你应该使用它们.

如果由于某种原因无法使用构造函数,则使用工厂函数:

Bar *baz = Bar::initWithPuppies();
Run Code Online (Sandbox Code Playgroud)

它将执行对象的分配和初始化,因此您不必new直接使用.

至于错误的原因,那是因为你无法隐式上转换.根据继承的性质,所有Bar对象也是Base对象.因此,C++将隐式地将指向派生类的指针转换为指向基类的指针.相反的是正确的:Base类是自动所有Bar类.因此,C++将正确地为您尝试转换继承层次结构时出错.

您必须明确使用a dynamic_cast来执行此类转换.您可以使用C风格的演员表或者a static_cast,但是只有在您完全确定该类型是您期望的类型时才能使用.