模板化虚拟函数有哪些替代方案?
这是我的设置案例的抽象:
class CParent
{
bool m_bExampleParentData = true;
public:
template< typename t > virtual operator t( ) = 0;
};
class CChild1: public CParent
{
char m_chExampleChild1Data = 'c';
public:
operator char & ( ) override
{
return m_chExampleChild1Data;
}
};
class CChild2: public CParent
{
int m_iExampleChild2Data = 17;
public:
operator int & ( ) override
{
return m_iExampleChild2Data;
}
};
这是我的用例的抽象:
int main( )
{
std::vector< CParent * > vecAbstractPointers;
CChild1 child1;
vecAbstractPointers.emplace_back( reinterpret_cast< CParent * >( &child1 ) );
CChild2 child2;
vecAbstractPointers.emplace_back( reinterpret_cast< CParent * >( &child2 ) );
*vecAbstractPointers[ 0 ] /*char( child1 )*/ = 'b';
*vecAbstractPointers[ 1 ] /*int( child2 )*/ = 8;
}
我敢肯定有些东西比这段代码愚蠢明显,而且简单得多,但是我一辈子都不会想到它。
这将有望实现通过父类中的虚函数分配子类成员的能力,而无需了解子类成员的类型。我认为自己没有什么可以做的,我也许可以使用标准(例如std::variant
或std::any
)来实现某些功能,但我想避免这种情况。我试图使结束代码尽可能不进行强制转换(因此隐式强制转换)。
答案 0 :(得分:1)
通过父类中的虚拟函数分配子类的成员,而无需了解子类的成员的类型
这在C ++中通常是不可能的。 C ++是一种静态类型的语言。因此,必须在编译时知道每个表达式的类型。模板也遵循此规则。它们只是允许根据特定类型生成函数/类/等。因此,对于带有类型参数T
的模板函数,可以生成无限数量的可能函数。编译器仅生成静态使用的代码。
这是静态多态性。
此模板功能生成也是为什么不允许virtual
模板功能的原因。根据定义,它们必须有无限多个版本,并且派生类必须实现每个版本。 virtual
机制通常依赖于函数的身份,而模板实际上并不存在。
virtual
函数表示动态/运行时多态。这些基于在基类中定义的原型,这些原型在派生类中实现。但是那些原型只是常规函数。具有完整功能签名(包括其返回类型)的功能。必须遵循C ++规则的签名:类型在编译时是已知的。
这样,实现您正在讨论的内容的唯一方法是,以一种使编译器不知道类型是什么,而源和目标却知道的方式来打包值。 std::any
是一个不错的工具。
答案 1 :(得分:1)
这就是我想出的,只需对您发布的代码进行最少的更改即可。
#include <iostream>
#include <vector>
// Base class to be able to hold pointers to derived class instances.
class CParent
{
bool m_bExampleParentData = true;
public:
// Add this to make sure deleting object through base class pointers works
// as well as dynamic_cast is supported.
virtual ~CParent() {}
};
// Base class to allow inheritance of specific conversion operators.
template <typename T>
class TParent
{
public:
virtual operator T() = 0;
};
// By inheriting from TParent<char&>, this class must support conversion
// to char& to allow instantation of class objects.
class CChild1: public CParent, public TParent<char&>
{
char m_chExampleChild1Data = 'c';
operator char & ( ) override
{
return m_chExampleChild1Data;
}
};
// By inheriting from TParent<int&>, this class must support conversion
// to int& to allow instantation of class objects.
class CChild2: public CParent, public TParent<int&>
{
int m_iExampleChild2Data = 17;
operator int & ( ) override
{
return m_iExampleChild2Data;
}
};
int main()
{
std::vector< CParent * > vecAbstractPointers;
CChild1 child1;
vecAbstractPointers.emplace_back( reinterpret_cast< CParent * >( &child1 ) );
CChild2 child2;
vecAbstractPointers.emplace_back( reinterpret_cast< CParent * >( &child2 ) );
// Rather ugly casts to allow assignment of 'b' and 8.
static_cast<char&>(*(dynamic_cast<TParent<char&>*>(vecAbstractPointers[0]))) = 'b';
static_cast<int&>(*(dynamic_cast<TParent<int&>*>(vecAbstractPointers[1]))) = 8;
// Rather ugly casts to allow extraction of 'b' and 8.
std::cout << static_cast<char&>(*(dynamic_cast<TParent<char&>*>(vecAbstractPointers[0]))) << std::endl;
std::cout << static_cast<int&>(*(dynamic_cast<TParent<int&>*>(vecAbstractPointers[1]))) << std::endl;
}
PS 请不要在实际应用中使用此类代码。我确信您要完成的工作会有更好的设计。
答案 2 :(得分:0)
class CParent
{
bool m_bExampleParentData = true;
public:
virtual operator int&( ) { exit(-1); }
virtual operator bool&( ) { exit(-1); }
};
template<class T>
class Child:public CParent
{
T t;
public:
operator T&() override { return t; }
};
using CChild1=Child<int>;
using CChild2=Child<bool>;
然后:
std::vector< CParent * > vecAbstractPointers;
CChild1 child1;
vecAbstractPointers.emplace_back( &child1 );
CChild2 child2;
vecAbstractPointers.emplace_back( &child2 );
*vecAbstractPointers[ 0 ] /*char( child1 )*/ = 'b';
*vecAbstractPointers[ 1 ] /*int( child2 )*/ = 8;
编译。
这是个坏主意。