c++ - 替代动态类型转换

标签 c++ dynamic

有没有在 C++ 中使用 dynamic_cast 的替代方法?

例如,在下面的代码中,我希望能够让 Cat 对象咕噜咕噜。但是只有 Cat 对象而不是 Dog 对象。我知道这不利于从 Mammal 派生类,因为它不是多态的,但我仍然想知道我是否可以在没有 dynamic_cast 的情况下做到这一点。

我的类(class)声明

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";}
};

主要

int main()
{

    Mammal *pMammal;

    pMammal = new Cat;

    pMammal->Purr();     //How would I call this without having to use dynamic_cast?

    return 0;
}

最佳答案

如果您知道有一组固定的实现,您可以创建 virtual为您进行转换的功能。这可能比 dynamic_cast 便宜.

所以:

struct Cat;
struct Mammal {
  virtual Cat* AsCat(){ return nullptr; }
};
struct Cat : Mammal {
  virtual Cat* AsCat() { return this; }
};

我用 template 完成了这个C++11 中的 tomfoolery,因此您甚至可以让它看起来像一个 Actor 。

#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";
}

Live Example

这可以清理以支持更标准的 fast_cast<Cat*>而不是 fast_cast<Cat> ,以及 fast_cast<Cat&> , 然后阻止直接访问 do_fast_cast通过将其设为私有(private)和fast_cast一个friend ,并允许一些手段有virtual在您需要的情况下继承。

但系统的核心在上面。您以单个 virtual 为代价获得转换为派生功能查找,而无需自己维护大部分机器。


替代实现:

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";
}

对于某些编译器来说,这可能更容易接受。 Live example .

请注意,对于一长串类型,上面的代码变得笨拙(在编译时和运行时),因为它依赖于线性继承。

二进制继承系统的编程会稍微复杂一些,但可以解决这个问题。在其中,您将要继承的事物列表拆分为两个大小相等的列表并从两者继承。工具快速转换必须继承自 Base通过虚拟中介。

关于c++ - 替代动态类型转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20792163/

相关文章:

c++使用通过数据包接收的 key 加密文本? key 沙皇?

mysql - 显示第二个表中条目数的动态值

c++ - 获取矩阵错误 cin>>

c++ - 计算合并排序算法的交换/比较次数

validation - Grails:如何使g:textfield只接受数字或字母?

javascript - 带有动态 img src 的 JS/HTML 图像转换器

sql - 在 plpgsql 中,如何使用可变数量的标识符创建和执行命令字符串?

c++ - 氏族库错误 LNK1104 : cannot open file 'clanCore-static-mt-debug.lib' ?

c++ - 两种使用默认构造函数的区别

c++ - 打包 BCD 的 Wireshark 解析器编码