动态铸造的替代方案 在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";}
};
三种变体:
要获得这些类型转换的完整参考和示例,请查找一些书籍和教程,例如:您正在处理一个指向类型
哺乳动物的指针,并且可能哺乳动物没有定义Purr()
。为了访问Purr()
,您必须将其强制转换为指向typeCat
的指针。你可以用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";
}