返回“this”的多态性派生的,来自 C++ 中的基类
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
好的,就到此为止。这不是您想要的语法。 C++ 中存在构造函数是有充分理由的,除非您有充分理由规避它们,否则您应该使用它们。
如果由于某种原因无法使用构造函数,请使用工厂函数:
它将执行对象的分配和初始化,因此您不必直接使用
new
。至于错误的原因,是因为你不能隐式上转换。根据继承的本质,所有
Bar
对象也是Base
对象。因此,C++ 会将指向派生类的指针隐式转换为指向基类的指针。反之则不然:Base
类并非自动成为所有Bar
类。因此,当您尝试向上转换继承层次结构时,C++ 将理所当然地给出一个错误。您必须显式使用
dynamic_cast
来执行此类转换。您可以使用 C 风格的强制转换或static_cast
,但只有当您绝对确定类型是您所期望的类型时,它们才会起作用。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:
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 alsoBase
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 allBar
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 astatic_cast
, but those will only work if you're absolutely certain that the type is what you expect it to be.您可能会发现 C++ 对协变返回类型的支持很有用。这意味着,如果在基类中定义一个返回
Base *
类型对象的函数,则可以重写该方法以使其返回Base*
或任何类型的对象。指向Base
派生类的指针。例如,这段代码是完全合法的:希望这有帮助!
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 aBase*
or any pointer to a derived class ofBase
. For example, this code is perfectly legal:Hope this helps!