动态铸造的替代方案 在C++中使用“动态DistaCase有别的选择吗?”p>

动态铸造的替代方案 在C++中使用“动态DistaCase有别的选择吗?”p>,c++,dynamic,C++,Dynamic,例如,在下面的代码中,我希望能够使Cat对象发出呜呜声。但是只有Cat对象,而不是Dog对象。我知道这不利于从哺乳动物派生类,因为它不是非常多态的,但我仍然想知道,如果没有动态转换,我是否可以这样做 我的类声明 class Mammal { public: virtual void Speak() const {cout << "Mammals yay!\n";} }; class Cat: public Mammal { publi

例如,在下面的代码中,我希望能够使
Cat
对象发出呜呜声。但是只有
Cat
对象,而不是
Dog
对象。我知道这不利于从
哺乳动物
派生类,因为它不是非常多态的,但我仍然想知道,如果没有
动态转换
,我是否可以这样做

我的类声明

class Mammal
{
       public: 
             virtual void Speak() const {cout << "Mammals yay!\n";}
};
class Cat: public Mammal
{
    public:
        void Speak() const{cout << "Meow\n";}
        void Purr() const {cout <"rrrrrrrr\n";}
};

class Dog: public Mammal
{
   public:
       void Speak() const{cout << "Woof!\n";}
};
三种变体:

  • 动态_cast,你应该已经知道了

  • 静态转换,即编译时转换,即a)检查类型的兼容性b)计算并考虑基类和派生类之间的偏移量c)没有运行时检查

  • 重新解释_转换,也是编译时转换,不需要任何类型检查和偏移量计算。小心使用-此强制转换可能会导致调试非常困难的bug


  • 要获得这些类型转换的完整参考和示例,请查找一些书籍和教程,例如:

    您正在处理一个指向类型
    哺乳动物
    的指针,并且可能
    哺乳动物
    没有定义
    Purr()
    。为了访问
    Purr()
    ,您必须将其强制转换为指向type
    Cat
    的指针。你可以用C风格的铸件或者<代码> DyjixCase来做这件事,而后者在C++中通常是更合适的事情。code>dynamic_cast
    还有一个优点,就是您可以在运行时使用它来测试您的
    Madamal
    对象是否是
    Cat
    ,因此您可以决定是否可以调用
    Purr()
    C++不支持发送消息,例如Objective C或Smalltalk。要调用一个方法,您需要有一个支持该方法的对象的静态类型句柄。您是否需要使用
    动态投射(指针)
    ,或者是否可以使用其他东西,例如
    静态投射(指针)
    ,这是一个单独的问题


    由于
    dynamic_cast()
    成本相对较高,并且尝试无限数量的不同类是不可行的,因此最好在使用访问者调用的基类中使用
    visit()
    方法。然而,这些只是获得正确类型引用的技术。

    如果您知道有一组固定的实现,您可以创建
    虚拟
    函数来为您进行转换。这比
    dynamic\u cast
    更便宜

    因此:

    我用C++11中的
    template
    Tom傻瓜做了这件事,所以你甚至可以让它看起来像一个演员

    #include <utility>
    #include <iostream>
    
    template<typename T>
    struct fast_castable_leaf {
      virtual T* do_fast_cast(T* unused=nullptr) { return nullptr; }
      virtual T const* do_fast_cast(T* unused=nullptr) const { return nullptr; }
      virtual ~fast_castable_leaf() {}
    };
    template<typename Tuple>
    struct fast_castable;
    template<template<typename...>class Tuple>
    struct fast_castable<Tuple<>> {
      virtual ~fast_castable() {}
    };
    template<template<typename...>class Tuple, typename T, typename... Ts>
    struct fast_castable<Tuple<T,Ts...>>:
      fast_castable_leaf<T>,
      fast_castable<Tuple<Ts...>>
    {};
    template<typename T> struct block_deduction { typedef T type; };
    template<typename T> using NoDeduction = typename block_deduction<T>::type;
    template<typename T>
    T* fast_cast( NoDeduction<fast_castable_leaf<T>>* src ) {
      return src->do_fast_cast();
    }
    template<typename T>
    T const* fast_cast( NoDeduction<fast_castable_leaf<T>> const* src ) {
      return src->do_fast_cast();
    }
    
    template<typename T, typename D>
    struct fast_cast_allowed : std::integral_constant<bool,
      std::is_base_of<T,D>::value || std::is_same<T,D>::value
    > {};
    
    template<typename D, typename B, typename Tuple>
    struct implement_fast_cast;
    
    template<typename D, typename B, template<typename...>class Tuple>
    struct implement_fast_cast<D,B,Tuple<>> : B {};
    template<typename D, typename B, template<typename...>class Tuple, typename T, typename... Ts>
    struct implement_fast_cast<D,B,Tuple<T,Ts...>> : implement_fast_cast<D, B, Tuple<Ts...>> {
    private:
      D* do_cast_work(std::true_type) { return static_cast<D*>(this); }
      D const* do_cast_work(std::true_type) const { return static_cast<D const*>(this); }
      std::nullptr_t do_cast_work(std::false_type) { return nullptr; }
      std::nullptr_t do_cast_work(std::false_type) const { return nullptr; }
    public:
      T* do_fast_cast( T* unused = nullptr ) override { return do_cast_work( fast_cast_allowed<T,D>() ); }
      T const* do_fast_cast( T* unused = nullptr ) const override { return do_cast_work( fast_cast_allowed<T,D>() ); }
    };
    
    对于某些编译器来说,这可能更容易接受

    请注意,对于一长串的类型,上面的方法会变得很笨拙(在编译时,也可能在运行时),因为它依赖于线性继承


    二进制继承系统的编程可能要复杂一些,但可以解决这个问题。在其中,您将要从中继承的内容列表拆分为两个大小相同的列表,并从这两个列表中继承。implement fast cast必须通过虚拟中介从
    Base
    继承。

    也许我在监督这个问题,但是如果您将方法声明为
    虚拟
    ,它是否会有所帮助?哦,是的。我将编辑我的代码。事实上,我之前是用笔和纸来做这件事的。实际上,它是从
    哺乳动物
    @H2CO3和
    虚拟
    派生而来的。您仍然只能调用指针类定义的内容,在本例中,除非基类有
    Purr(),否则您将无法调用
    Purr()
    也一样。@Mario我假设哺乳动物也有这些方法。。。但这几乎没有什么意义。C++支持发送消息是很好的:你只需要自己实现消息架构,而不是在…中烘烤…这个例子是用MIWW 4.92.32位编译的,而不是用MSVC 2013 64位编译的。我得到错误C2504“fast_castable:基类未定义”。我不明白为什么。@Carlton嗯,因为MSVC2013不是C++11编译器?作为猜测,我会让事情变得不那么花哨:删除
    templateclass Tuple
    ,将
    类型的定义移动到
    fast\u castable
    上方,在其下方使用
    类型而不是
    Tuple
    。可能还需要对implement\u fast\u cast进行类似的修改。@Carlton Simpler版本发布。MSVC2013是如何治疗的?
    struct Cat;
    struct Mammal {
      virtual Cat* AsCat(){ return nullptr; }
    };
    struct Cat : Mammal {
      virtual Cat* AsCat() { return this; }
    };
    
    #include <utility>
    #include <iostream>
    
    template<typename T>
    struct fast_castable_leaf {
      virtual T* do_fast_cast(T* unused=nullptr) { return nullptr; }
      virtual T const* do_fast_cast(T* unused=nullptr) const { return nullptr; }
      virtual ~fast_castable_leaf() {}
    };
    template<typename Tuple>
    struct fast_castable;
    template<template<typename...>class Tuple>
    struct fast_castable<Tuple<>> {
      virtual ~fast_castable() {}
    };
    template<template<typename...>class Tuple, typename T, typename... Ts>
    struct fast_castable<Tuple<T,Ts...>>:
      fast_castable_leaf<T>,
      fast_castable<Tuple<Ts...>>
    {};
    template<typename T> struct block_deduction { typedef T type; };
    template<typename T> using NoDeduction = typename block_deduction<T>::type;
    template<typename T>
    T* fast_cast( NoDeduction<fast_castable_leaf<T>>* src ) {
      return src->do_fast_cast();
    }
    template<typename T>
    T const* fast_cast( NoDeduction<fast_castable_leaf<T>> const* src ) {
      return src->do_fast_cast();
    }
    
    template<typename T, typename D>
    struct fast_cast_allowed : std::integral_constant<bool,
      std::is_base_of<T,D>::value || std::is_same<T,D>::value
    > {};
    
    template<typename D, typename B, typename Tuple>
    struct implement_fast_cast;
    
    template<typename D, typename B, template<typename...>class Tuple>
    struct implement_fast_cast<D,B,Tuple<>> : B {};
    template<typename D, typename B, template<typename...>class Tuple, typename T, typename... Ts>
    struct implement_fast_cast<D,B,Tuple<T,Ts...>> : implement_fast_cast<D, B, Tuple<Ts...>> {
    private:
      D* do_cast_work(std::true_type) { return static_cast<D*>(this); }
      D const* do_cast_work(std::true_type) const { return static_cast<D const*>(this); }
      std::nullptr_t do_cast_work(std::false_type) { return nullptr; }
      std::nullptr_t do_cast_work(std::false_type) const { return nullptr; }
    public:
      T* do_fast_cast( T* unused = nullptr ) override { return do_cast_work( fast_cast_allowed<T,D>() ); }
      T const* do_fast_cast( T* unused = nullptr ) const override { return do_cast_work( fast_cast_allowed<T,D>() ); }
    };
    
    struct Dog;
    struct Cat;
    struct Moose;
    template<typename...>struct Types {};
    typedef Types<Dog, Cat, Moose> Mammal_Types;
    
    // A Mammal can be fast-casted to any of the Mammal_Types:
    struct Mammal : fast_castable<Mammal_Types>
    {};
    
    // Cat wants to implement any legal fast_casts it can for Mammal in the
    // set of Mammal_Types.  You can save on overhead by doing Types<Cat> instead
    // of Mammal_Types, but this is less error prone:
    struct Cat : implement_fast_cast< Cat, Mammal, Mammal_Types >
    {};
    
    int main() {
      Cat c;
      Mammal* m=&c;
      // so m is a pointer to a cat, but looks like a mammal.  We use
      // fast cast in order to turn it back into a Cat:
      Cat* c2 = fast_cast<Cat>(m);
      // and we test that it fails when we try to turn it into a Dog:
      Dog* d2 = fast_cast<Dog>(m);
      // This prints out a pointer value for c2, and 0 for d2:
      std::cout << c2 << "," << d2 << "\n";
    }
    
    template<class...>struct types{using type=types;};
    
    template<typename T>
    struct fast_castable_leaf {
      virtual T* do_fast_cast(T* unused=nullptr) { return nullptr; }
      virtual T const* do_fast_cast(T* unused=nullptr) const { return nullptr; }
      virtual ~fast_castable_leaf() {}
    };
    template<class Tuple>
    struct fast_castable;
    template<>
    struct fast_castable<types<>> {
      virtual ~fast_castable() {}
    };
    template<class T0, class...Ts>
    struct fast_castable<types<T0, Ts...>>:
      fast_castable_leaf<T0>,
      fast_castable<types<Ts...>>
    {};
    template<class T> struct block_deduction { typedef T type; };
    template<class T> using NoDeduction = typename block_deduction<T>::type;
    template<class T>
    T* fast_cast( NoDeduction<fast_castable_leaf<T>>* src ) {
      return src->do_fast_cast();
    }
    template<class T>
    T const* fast_cast( NoDeduction<fast_castable_leaf<T>> const* src ) {
      return src->do_fast_cast();
    }
    
    template<class T, class D>
    struct fast_cast_allowed : std::integral_constant<bool,
      std::is_base_of<T,D>::value || std::is_same<T,D>::value
    > {};
    
    template<class Self, class Base, class Types>
    struct implement_fast_cast;
    
    template<class Self, class Base>
    struct implement_fast_cast<Self,Base,types<>> : Base {
    private:
      template<class, class, class>
      friend struct implement_fast_cast;
    
      Self* do_cast_work(std::true_type) { return static_cast<Self*>(this); }
      Self const* do_cast_work(std::true_type) const { return static_cast<Self const*>(this); }
      std::nullptr_t do_cast_work(std::false_type) { return nullptr; }
      std::nullptr_t do_cast_work(std::false_type) const { return nullptr; }
    };
    
    template<class Self, class Base, class T0, class... Ts>
    struct implement_fast_cast<Self,Base,types<T0,Ts...>> :
      implement_fast_cast<Self, Base, types<Ts...>>
    {
    public:
      T0* do_fast_cast( T0* unused = nullptr ) override { return this->do_cast_work( fast_cast_allowed<T0,Self>() ); }
      T0 const* do_fast_cast( T0* unused = nullptr ) const override { return this->do_cast_work( fast_cast_allowed<T0,Self>() ); }
    };
    
    struct Dog;
    struct Cat;
    struct Moose;
    typedef types<Dog, Cat, Moose> Mammal_Types;
    
    struct Mammal : fast_castable<Mammal_Types>
    {};
    
    struct Cat : implement_fast_cast< Cat, Mammal, Mammal_Types >
    {};
    
    int main() {
      Cat c;
      Mammal* m=&c;
      Cat* c2 = fast_cast<Cat>(m);
      Dog* d2 = fast_cast<Dog>(m);
      std::cout << c2 << "," << d2 << "\n";
    }