返回“this”的多态性派生的,来自 C++ 中的基类

发布于 2024-12-03 14:43:12 字数 2319 浏览 0 评论 0原文

C++ 中的多态性存在一些问题。我正在尝试创建一个相当奇怪的语法来初始化类,但当我从基类方法返回“this”时,我似乎丢失了新创建的派生类。

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

我想要这样的语法:

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

最好使用模板并需要像这样进行转换:

initWithPuppies<Bar *>();

是的,我知道这很奇怪。但这是有原因的,“最佳实践”不适用于这种情况。将此视为“假设”。我知道你可能应该:

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

但我需要以前的语法。

伪代码:

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();

编辑:

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

Bar *baz = (Bar::create())->initWithPuppies();

那就更好了,但我不知道如何在基类中创建派生类的新实例没有类型转换:

Bar *baz = (Bar::create<Bar *>())->initWithPuppies();

我的答案:(在 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();

Having some trouble with polymorphism in C++. I'm trying to create a rather strange syntax for initializing a class but it appears I'm losing the newly created derived class when I return "this" from a base class method.

In the pseudo code below, I need to have Base::initWithPuppies() able to do some default action and return the derived class that it is calling from.

I want to have this syntax:

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

Preferably without using templates and needing to cast like:

initWithPuppies<Bar *>();

Yeah, I know it's rather wack. But there's a reason for it and "best practices" is not applying in this situation. Consider this just a "what if". I know you should probably:

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

But I need the former syntax.

Pseudo code:

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();

EDIT:

If it was somehow possible to have this syntax:

Bar *baz = (Bar::create())->initWithPuppies();

That would be even better, but I couldn't figure out how to have create in the base class create a new instance of a derived without typecasting:

Bar *baz = (Bar::create<Bar *>())->initWithPuppies();

MY ANSWER: (can't answer my own for 8 hours)

Although Nicol Bolas is correct and as I stated the syntax I want to use is bad practice, if you really do need to use a similar syntax as I do (don't ask...) then you can do this:

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();

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦里°也失望 2024-12-10 14:43:12

我想要这样的语法:

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

好的,就到此为止。这不是您想要的语法。 C++ 中存在构造函数是有充分理由的,除非您有充分理由规避它们,否则您应该使用它们。

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

Bar *baz = Bar::initWithPuppies();

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

至于错误的原因,是因为你不能隐式上转换。根据继承的本质,所有 Bar 对象也是 Base 对象。因此,C++ 会将指向派生类的指针隐式转换为指向基类的指针。反之则不然:Base并非自动成为所有Bar 类。因此,当您尝试向上转换继承层次结构时,C++ 将理所当然地给出一个错误。

您必须显式使用 dynamic_cast 来执行此类转换。您可以使用 C 风格的强制转换或 static_cast,但只有当您绝对确定类型是您所期望的类型时,它们才会起作用。

I want to have this syntax:

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

OK, stop right there. That is not the syntax you want. Constructors exist in C++ for a good reason, and unless you have a very good reason for circumventing them, you should use them.

If you can't use a constructor for some reason, then use a factory function:

Bar *baz = Bar::initWithPuppies();

It will do the allocation and initialization of the object, so you don't have to use new directly.

As to the reason for the error, it is because you cannot implicitly up-convert. All Bar objects are also Base objects, by the nature of inheritance. Therefore, C++ will implicitly convert pointers to a derived class into pointers to a base class. The reverse is not true: Base classes are not automatically all Bar classes. Therefore, C++ will rightfully give you an error for attempting to convert up the inheritance hierarchy.

You have to explicitly use a dynamic_cast to do this kind of conversion. You could use a C-style cast or a static_cast, but those will only work if you're absolutely certain that the type is what you expect it to be.

计㈡愣 2024-12-10 14:43:12

您可能会发现 C++ 对协变返回类型的支持很有用。这意味着,如果在基类中定义一个返回 Base * 类型对象的函数,则可以重写该方法以使其返回 Base* 或任何类型的对象。指向Base派生类的指针。例如,这段代码是完全合法的:

class Base {
public:
    virtual ~Base() {} // Polymorphic classes need virtual destructors!
    virtual Base* initWithPuppies() = 0;
}

class Derived: public Base {
public:
    /* Note that the return type is Derived*, but it's still an override! */
    virtual Derived* initWithPuppies() {
        return this;
    }
}

/* Perfectly legal code; Derived::initWithPuppies() returns a Derived* */
Derived* d = (new Derived)->initWithPuppies();

希望这有帮助!

Something you may find useful is C++'s support for covariant return types. This means that if in a base class you define a function that returns an object of type Base *, you can override that method to have it return either a Base* or any pointer to a derived class of Base. For example, this code is perfectly legal:

class Base {
public:
    virtual ~Base() {} // Polymorphic classes need virtual destructors!
    virtual Base* initWithPuppies() = 0;
}

class Derived: public Base {
public:
    /* Note that the return type is Derived*, but it's still an override! */
    virtual Derived* initWithPuppies() {
        return this;
    }
}

/* Perfectly legal code; Derived::initWithPuppies() returns a Derived* */
Derived* d = (new Derived)->initWithPuppies();

Hope this helps!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文