使用dynamic_cast<T>的时机是什么?

huangapple go评论71阅读模式
英文:

When to use dynamic_cast<T>?

问题

I know about dynamic_cast but seriously wondering when to use that?

我了解dynamic_cast,但真的想知道何时使用它?

Why not ALWAYS add the appropriate function to the base class and always have access to the function you need?

为什么不总是将适当的函数添加到基类中,以便始终可以访问所需的函数?

Does this have any performance aspects?

这是否涉及性能方面的问题?

I wrote a small example to illustrate this. Without the pure virtual function myUniqueFunc() in the base class A, the function in the derived classes can only be called with a dynamic_cast. So I would include ALWAYS the function in the base class...

我写了一个小例子来说明这一点。如果基类A中没有纯虚函数myUniqueFunc(),则只能使用dynamic_cast调用派生类中的函数。因此,我会始终将该函数包含在基类中...

In addition, a dynamic_cast requires a lot of overhead and thus computing time.

此外,dynamic_cast需要大量的开销,因此需要计算时间。

(以下是代码部分,不需要翻译。)

#include <iostream>
#include <vector>

class A
{
public:
    virtual void printSomething() { std::cout << "class A: hello." << std::endl; };
    virtual void myUniqueFunc() = 0 ;
    virtual ~A() {};
};

class B : public A
{
public:
    void printSomething() override { std::cout << "class B: hello." << std::endl; };
    void myUniqueFunc() { std::cout << "class B: Only I can do this..." << std::endl; }
    B() {};
    virtual ~B() {};

};

class C : public A
{
public:
    //void printSomething() override { std::cout << "class C: hello." << std::endl; };
    void myUniqueFunc() { std::cout << "class C: Only I can do this..." << std::endl; }
    C() {};
    ~C() {};
};

int main()
{
    std::vector<std::unique_ptr<A>> myObjects;
    myObjects.emplace_back(std::make_unique<B>());
    myObjects.emplace_back(std::make_unique<C>());
    myObjects.emplace_back(std::make_unique<B>());
    myObjects.emplace_back(std::make_unique<C>());
    myObjects.emplace_back(std::make_unique<B>());
    myObjects.emplace_back(std::make_unique<C>());

    // 1. fast solution via complete virtual functions in base class
    // iterate over all Objects (common functions only
    for (auto& curObjects : myObjects)
    {
        curObjects->printSomething();
        curObjects->myUniqueFunc();
    }

    // 2. slow solution via incomplete virtual functions in base class and downcast to derived classes
    // iterate over all Objects (and calls the special func from the derived classes only)
    for (auto& curObjects : myObjects)
    {
        // downcast to the derived classes to get the unique functions
        if (typeid(curObjects) == typeid(B))
        {
            B& aBClass = dynamic_cast<B&>(*curObjects);
            aBClass.myUniqueFunc();
        }

        if (typeid(curObjects) == typeid(C))
        {
            // downcast to the derived classes to get the unique functions
            C& aCClass = dynamic_cast<C&>(*curObjects);
            aCClass.myUniqueFunc();
        }
    }

    return 0;
}
英文:

I know about dynamic_cast but seriously wondering when to use that?
Why not ALWAYS add the appropriate function to the base class and always have access to the function you need?

Does this have any performance aspects?

I wrote a small example to illustrate this.
Without the pure virtual function myUniqueFunc() in the base class A, the function in the derived classes can only be called with a dynamic_cast.
So I would include ALWAYS the function in the base class...

In addition, a dynamic_cast requires a lot of overhead and thus computing time.


#include &lt;iostream&gt;
#include &lt;vector&gt;
class A
{
public:
virtual void printSomething() { std::cout &lt;&lt; &quot;class A: hello.&quot; &lt;&lt; std::endl; };
virtual void myUniqueFunc() = 0 ;
virtual ~A() {};
};
class B : public A
{
public:
void printSomething() override { std::cout &lt;&lt; &quot;class B: hello.&quot; &lt;&lt; std::endl; };
void myUniqueFunc() { std::cout &lt;&lt; &quot;class B: Only I can do this...&quot; &lt;&lt; std::endl; }
B() {};
virtual ~B() {};
};
class C : public A
{
public:
//void printSomething() override { std::cout &lt;&lt; &quot;class C: hello.&quot; &lt;&lt; std::endl; };
void myUniqueFunc() { std::cout &lt;&lt; &quot;class C: Only I can do this...&quot; &lt;&lt; std::endl; }
C() {};
~C() {};
};
int main()
{
std::vector&lt;std::unique_ptr&lt;A&gt;&gt; myObjects;
myObjects.emplace_back(std::make_unique&lt;B&gt;());
myObjects.emplace_back(std::make_unique&lt;C&gt;());
myObjects.emplace_back(std::make_unique&lt;B&gt;());
myObjects.emplace_back(std::make_unique&lt;C&gt;());
myObjects.emplace_back(std::make_unique&lt;B&gt;());
myObjects.emplace_back(std::make_unique&lt;C&gt;());
// 1. fast solution via complete virtual functions in base class
// iterate over all Objects (common functions only
for (auto&amp; curObjects : myObjects)
{
curObjects-&gt;printSomething();
curObjects-&gt;myUniqueFunc();
}
// 2. slow solution via incomplete virtual functions in base class and downcast to derived classes
// iterate over all Objects (and calls the special func from the derived classes only)
for (auto&amp; curObjects : myObjects)
{
// downcast to the derived classes to get the unique functions
if (typeid(curObjects) == typeid(B))
{
B&amp; aBClass = dynamic_cast&lt;B&amp;&gt;(*curObjects);
aBClass.myUniqueFunc();
}
if (typeid(curObjects) == typeid(C))
{
// downcast to the derived classes to get the unique functions
C&amp; aCClass = dynamic_cast&lt;C&amp;&gt;(*curObjects);
aCClass.myUniqueFunc();
}
}
return 0;
}

答案1

得分: 1

dynamic_cast 允许向兄弟类型进行转换,例如:

struct IFoo
{
   virtual ~IFoo() = default;
   virtual void foo() = 0;
};

struct IBar
{
   virtual ~IBar() = default;
   virtual void bar() = 0;
   void fooBar() {
       if (auto* foo = dynamic_cast<IFoo*>(this)) {
           foo->foo();
       }
       bar();
   }
};

struct D1 : IBar { /*...*/};
struct D2 : IFoo, IBar { /*...*/ };

演示

英文:

dynamic_cast allows casting to sibling, for example:

struct IFoo
{
virtual ~IFoo() = default;
virtual void foo() = 0;
};
struct IBar
{
virtual ~IBar() = default;
virtual void bar() = 0;
void fooBar() {
if (auto* foo = dynamic_cast&lt;IFoo*&gt;(this)) {
foo-&gt;foo();
}
bar();
}
};
struct D1 : IBar { /*...*/};
struct D2 : IFoo, IBar { /*...*/ };

Demo

答案2

得分: 0

动态转型在处理许多不同对象的引擎中非常流行,例如在HTML引擎中。给定以下代码:

if(auto audio = dynamic_cast<HTMLAudioElement *>(element); audio)
    audio->Play();

虽然你可以将Play添加为HTMLElement的虚拟函数,但由于有许多类型的元素具有它们自己的函数,你最终会得到一个庞大的HTMLElement源文件。

英文:

Dynamic cast is very popular in engines that handle a lot of different objects, for example in html engines.
Given the following code:

if(auto audio = dynamic_cast&lt;HTMLAudioElement *&gt;(element); audio)
audio-&gt;Play();

Although you can add Play as a virtual function of HTMLElement, there are so many types of elements with their own functions that you will end up with a huge HTMLElement source file.

答案3

得分: 0

基类可能来自无法更改的库。

例如,我们在工作中制作CAD,但我们场景对象的基类来自我们无法控制的框架。而且我们的CAD是医学领域的,而框架与医学无关,所以我们的医学功能在那里没有意义。

这还使您的代码更具模块化性。您可以拥有一个模块(也许是在运行时加载的插件),引入一个新的派生类以及用于处理它的代码。很好地能够添加/删除此模块而不触及基类。

英文:

The base class might come from a library that you can't change.

For example, we make a CAD at work, but the base class for our scene objects comes from a framework that we don't control. And our CAD is medical, while the framework has nothing to do with medicine, so none of our medical functions would make sense in there.

This also makes your code more modular. You can have a module (perhaps a plugin loaded at runtime) that introduces a new derived class along with code for processing it. It's nice to be able to add/remove this module without touching the base classes.

huangapple
  • 本文由 发表于 2023年5月13日 23:12:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/76243442.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定