我一直在阅读关于类模板,专业化和继承的内容,但其他地方提供的示例都没有给我提供我所需要的东西。所以我把这个简单的例子放在一起来说明我的具体要求。
背景
说我有class A
,其中包含class B
的实例。但是,有两种不同类型的B
,我在enum class
(类型1和类型2)中定义,所以我需要两个单独的class B
版本,其中有一些特定的成员到那种B
。有两种可能的解决方案:
class B_Type1
和class B_Type2
。因此,基类包含公共成员,派生类具有自己的附加成员。问题:在A
中,我需要指定我需要的B
(B_Type1
或B_Type2
),这意味着我需要一个基础和两个派生A的课程也是如此。
由于我的实际程序中的层次结构由四个类而不是两个类组成,所以这一切都变得更糟。所以我必须为所有四个类创建基类和派生类!
B
。这样我只有一个班级B
,所以我也会临时A
,不需要基础或派生类,鲍勃是你的叔叔。问题:类型1和类型2具有共享成员但也有不同的成员,因此我必须专门化模板(template<> B<Type1>
和template<> B<Type2>
。但这意味着我必须在两者中实现共同成员特。
要求
用户应该能够通过提供仅 A
作为模板参数,使用两种B
中的一种来实例化enum class
。他们应该有权访问与class B
值对应的专门enum
成员。用户应该只能看到一个类型A的类(而不是A_Type1
和A_Type2
以及分别为B_Type1
和B_Type2
)。从我的角度来看,我不想在单独的模板专业化中实现B
的通用成员,因此我需要一种方法将普通成员放入单个类中,但是其他成员仍然应该驻留在单独的课程。
暂定解决方案
我提出了以下解决方案。尽管我对模板和继承有了基本的了解和理解,但我对结果非常满意。它为用户提供了集中的类A
和B
,因此他们不必担心专业化问题。对我来说,作为维护者,好处是我有一个地方可以坚持每个类的公共成员,同时仍然提供对相应类型的类的其他成员的访问,而不是另一个。很明显,一个问题是对象大小,这就是为什么我只需要那些与特定类型相关的成员。解决方案违背了我迄今为止看到的每个例子 - 基本上,应该是&#34; base&#34; class(例如class B
)继承自&#34; derived&#34;课程(B_Type1
和B_Type2
)。但是,由于特定的模板特化,根据提供的模板参数,实例化两个类B_Type1
和B_Type2
中的一个。
如果有任何部分不清楚,请告诉我,我会尝试详细说明。
问题
我是否忽略了与此代码相关的任何可怕的隐藏警告等待我最不期望的时候跳起来咬我?我不想花一个星期来重构我的代码,只是为了发现它带来了一些可怕的C ++黑暗面。
#include <iostream>
enum class ClassBType
{
Type1,
Type2
};
template<ClassBType BT>
class B_Type1
{
};
template<ClassBType BT>
class B_Type2
{
};
template<ClassBType BT>
class A_Type1
{
};
template<ClassBType BT>
class A_Type2
{
};
template<>
class B_Type1<ClassBType::Type1>
{
public:
int type_1_specific_item_1 = 1;
float type_2_specific_item_2 = 1.0;
std::string dummy_1 = "Dummy var 1";
std::string dummy_2 = "Dummy var 2";
std::string dummy_3 = "Dummy var 3";
std::string class_B_type_1 = "Type 1";
inline int get_type_1_specific_item_1()
{
return type_1_specific_item_1;
}
inline float get_type_1_specific_item_2()
{
return type_2_specific_item_2;
}
inline std::string get_dummy_1()
{
return dummy_1;
}
inline std::string get_dummy_2()
{
return dummy_2;
}
inline std::string get_dummy_3()
{
return dummy_3;
}
};
template<>
class B_Type2<ClassBType::Type2>
{
public:
int type_2_specific_item_1 = 2;
float type_2_specific_item_2 = 2.0;
std::string class_B_type_2 = "Type 2";
int get_type_2_specific_item_1()
{
return type_2_specific_item_1;
}
float get_type_2_specific_item_2()
{
return type_2_specific_item_2;
}
};
template<ClassBType BT>
class B : public B_Type1<BT>, public B_Type2<BT>
{
public:
// Common to both Type 1 and Type 2
ClassBType d_type = BT;
std::string get_type()
{
switch (d_type)
{
case ClassBType::Type1:
return "Type 1";
break;
case ClassBType::Type2:
return "Type 2";
break;
}
}
};
template<>
class A_Type1<ClassBType::Type1>
{
public:
std::string class_A_type_1 = "Type 1";
};
template<>
class A_Type2<ClassBType::Type2>
{
public:
std::string class_A_type_2 = "Type 2";
};
template<ClassBType BT>
class A : public A_Type1<BT>, public A_Type2<BT>
{
public:
B<BT> b_inst;
};
int main()
{
A<ClassBType::Type1> obj_a_type_1;
std::cout << "Type of object B: " << obj_a_type_1.b_inst.get_type() << std::endl;
std::cout << "Type of object A: " << obj_a_type_1.class_A_type_1 << std::endl;
std::cout << "Dummy var 1 from object B: " << obj_a_type_1.b_inst.get_dummy_1() << std::endl;
std::cout << "Dummy var 2 from object B: " << obj_a_type_1.b_inst.get_dummy_2() << std::endl;
std::cout << "Dummy var 3 from object B: " << obj_a_type_1.b_inst.get_dummy_3() << std::endl;
std::cout << "Specific item 1 from B: " << obj_a_type_1.b_inst.get_type_1_specific_item_1() << std::endl;
std::cout << "Specific item 1 from B: " << obj_a_type_1.b_inst.get_type_1_specific_item_2() << std::endl;
std::cout << "Size of object A: " << sizeof(obj_a_type_1) << std::endl;
std::cout << std::endl;
A<ClassBType::Type2> obj_a_type_2;
std::cout << "Type of object B: " << obj_a_type_2.b_inst.get_type() << std::endl;
std::cout << "Type of object A: " << obj_a_type_2.class_A_type_2 << std::endl;
std::cout << "Specific item 1 from B: " << obj_a_type_2.b_inst.get_type_2_specific_item_1() << std::endl;
std::cout << "Specific item 1 from B: " << obj_a_type_2.b_inst.get_type_2_specific_item_2() << std::endl;
std::cout << "Size of object A: " << sizeof(obj_a_type_2) << std::endl;
// This produces a compilation error, which is good:
// std::cout << obj_a_type_2.b_inst.get_dummy_1() << std::endl;
return 0;
}
这将打印以下内容:
Type of object B: Type 1
Type of object A: Type 1
Dummy var 1 from object B: Dummy var 1
Dummy var 2 from object B: Dummy var 2
Dummy var 3 from object B: Dummy var 3
Specific item 1 from B: 1
Specific item 1 from B: 1
Size of object A: 56
Type of object B: Type 2
Type of object A: Type 2
Specific item 1 from B: 2
Specific item 1 from B: 2
Size of object A: 32