dynamic_cast的继承和使用
假设我有如下 3 个类(因为这是一个示例,它将无法编译!):
class Base
{
public:
Base(){}
virtual ~Base(){}
virtual void DoSomething() = 0;
virtual void DoSomethingElse() = 0;
};
class Derived1
{
public:
Derived1(){}
virtual ~Derived1(){}
virtual void DoSomething(){ ... }
virtual void DoSomethingElse(){ ... }
virtual void SpecialD1DoSomething{ ... }
};
class Derived2
{
public:
Derived2(){}
virtual ~Derived2(){}
virtual void DoSomething(){ ... }
virtual void DoSomethingElse(){ ... }
virtual void SpecialD2DoSomething{ ... }
};
我想根据某些直到运行时才可用的设置来创建 Derived1 或 Derived2 的实例。
由于我在运行时之前无法确定派生类型,那么您认为以下做法是不好的做法吗?...
class X
{
public:
....
void GetConfigurationValue()
{
....
// Get configuration setting, I need a "Derived1"
b = new Derived1();
// Now I want to call the special DoSomething for Derived1
(dynamic_cast<Derived1*>(b))->SpecialD1DoSomething();
}
private:
Base* b;
};
我通常读到 Dynamic_cast 的使用不好,但正如我所说,我不知道 在运行时之前要创建哪种类型。请帮忙!
Suppose I have 3 classes as follows (as this is an example, it will not compile!):
class Base
{
public:
Base(){}
virtual ~Base(){}
virtual void DoSomething() = 0;
virtual void DoSomethingElse() = 0;
};
class Derived1
{
public:
Derived1(){}
virtual ~Derived1(){}
virtual void DoSomething(){ ... }
virtual void DoSomethingElse(){ ... }
virtual void SpecialD1DoSomething{ ... }
};
class Derived2
{
public:
Derived2(){}
virtual ~Derived2(){}
virtual void DoSomething(){ ... }
virtual void DoSomethingElse(){ ... }
virtual void SpecialD2DoSomething{ ... }
};
I want to create an instance of Derived1 or Derived2 depending on some setting that is not available until run-time.
As I cannot determine the derived type until run-time, then do you think the following is bad practice?...
class X
{
public:
....
void GetConfigurationValue()
{
....
// Get configuration setting, I need a "Derived1"
b = new Derived1();
// Now I want to call the special DoSomething for Derived1
(dynamic_cast<Derived1*>(b))->SpecialD1DoSomething();
}
private:
Base* b;
};
I have generally read that usage of dynamic_cast is bad, but as I said, I don't know
which type to create until run-time. Please help!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
为什么不通过将派生指针分配给基指针来延迟“丢弃”一些类型信息的时刻:
Why not delay the moment at which you "throw away" some if the type information by assigning a pointer to derived to a pointer to base:
虚函数的要点在于,一旦拥有正确类型的对象,您就可以调用正确的函数,而无需知道该对象是哪个派生类——您只需调用虚函数,它就会执行以下操作:正确的事情。
当您有一个派生类定义了基类中不存在的不同内容时,您只需要一个
dynamic_cast
,并且您需要/想要考虑到额外的东西。例如:
现在,如果您只想调用
do_something()
,则完全不需要dynamic_cast
。例如,您可以拥有一个Base *
集合,只需对每个集合调用do_something()
即可,而不用关心该对象是否真的是一个基础
或派生
。当/如果您有一个
Base *
,并且您想要调用do_something_else()
,那么您可以使用dynamic_cast 来确定对象本身是否真的是一个
Derived
以便您可以调用它。The point of virtual functions is that once you have the right kind of object, you can call the right function without knowing which derived class this object is -- you just call the virtual function, and it does the right thing.
You only need a
dynamic_cast
when you have a derived class that defines something different that's not present in the base class, and you need/want to take the extra something into account.For example:
Now, if you just want to call
do_something()
, adynamic_cast
is completely unnecessary. For example, you can have a collection ofBase *
, and just invokedo_something()
on every one, without paying any attention to whether the object is really aBase
or aDerived
.When/if you have a
Base *
, and you want to invokedo_something_else()
, then you can use adynamic_cast
to figure out whether the object itself is really aDerived
so you can invoke that.使用dynamic_cast本身并不是一个坏习惯。不恰当地使用它是不好的做法,即在并不真正需要的地方使用它。
以这种方式使用它也是一个不好的做法:
原因:dynamic_cast(b) 可能返回 NULL。
使用dynamic_cast时,您必须格外小心,因为不能保证b实际上是Derived1类型而不是Derived2类型:
您必须检查dynamic_cast是否确实成功。有两种方法可以做到这一点:在演员之前和之后检查。在转换之前,您可以通过 RTTI 检查您尝试转换的指针是否实际上是您期望的指针:
事后检查实际上更简单一些:
我还想说,尝试在同时保存打字是一种不好的做法用 C++ 编程。 C++ 中的许多功能似乎完全可以用更短的类型来表示(即让您感觉“NULL 永远不会在这里发生”),但事后调试起来却很痛苦。 ;)
Using dynamic_cast is not bad practice per se. It's bad practice to use it inappropriately, i.e. where it's not really needed.
It's also a bad practice to use it this way:
Reason: dynamic_cast(b) may return NULL.
When using dynamic_cast, you have to be extra careful, because it's not guaranteed, that b is actually of type Derived1 and not Derived2:
You have to check if dynamic_cast is actually successful. There are two ways of doing it: checking it before and after the cast. Before the cast you can check if the pointer you're trying to cast is actually the one you expect via RTTI:
Checking it post-factum is actually a bit simpler:
I'd also say it's a bad practice to try and save typing while programming in C++. There are many features in C++ than seem to be completely fine to be typed shorter (i.e. makes you feel 'that NULL will never happen here'), but turn out to be a pain in the ass to debug afterwards. ;)
您可能需要考虑避免使用dynamic_cast的其他一些事情
来自Effective C++(第三版) - Item 35 虚拟函数的替代方案 -
Some other things you might like to consider to avoid the use of dynamic_cast
From Effective C++ (Third Edition) - Item 35 Alternatives to virtual functions -
有一个名为 工厂模式 的模式适合这种情况。这允许您根据某些输入参数返回正确类的实例。
享受!
There is a pattern named Factory Pattern that would fit this scenario. This allows you to return an instance of the correct class based on some input parameter.
Enjoy!
有什么问题:
或者我错过了什么?
我可以建议,当你发布这样的问题时,你(和其他人)将你的类命名为 A、B、C 等,并将你的函数命名为 f1()、f2() 等。这让回答你问题的人变得更容易。
What is wrong with:
Or am I missing something?
And can OI suggest that when posting questions like this you (and others) name your classes A, B, C etc. and your functions things like f1(), f2() etc. It makes life a lot easier for people answering your questions.
避免
dynamic_cast
的一种方法是使用一个虚拟蹦床函数“SpecialDoSomething”,其派生多态实现调用该特定派生类的“SpecialDxDoSomething()”,该函数可以是您想要的任何非基类名称。它甚至可以调用多个函数。One way to avoid
dynamic_cast
is to have a virtual trampoline function "SpecialDoSomething" whose derived polymorphic implementation calls that particular derived class's "SpecialDxDoSomething()" which can be whatever non-base class name you desire. It can even call more than one function.