通过宏将父类protected函数在子类中提升为public
1.描述
在开发过程中遇到一个问题:有两个功能相像,数据结构类似的类存在,但是这两个类都有一些特别的函数与数据,且对于相近的数据,有一个类具备set系列的函数,另一个类只需要get系列的函数。
此时通常的处理过程是抽象出来一个基类,再特化出来两个子类进行各自的数据处理,为了解决set、get函数的权限问题,且将基类中所有与数据处理相关的函数设置为protected类型。
如此一来,如果在项目中如果有其他类需要使用到上述基类中的protected类型函数,则只需要在对应的子类中将其调整为public类型,即可访问。
2.相关
2.1 获取可变参数个数
//MSVC 下需要添加展开的这一步,否则会编译不过
#define M_Expand(...) __VA_ARGS__
//截断作用,获取第N位参数的索引
#define M_Args_N( \
_1, _2, _3, _4, _5, \
N,...) N
//获取参数个数
#define M_Args_Count(...) \
M_Expand(M_Args_N( \
__VA_ARGS__, \
5, 4, 3, 2, 1 \
))
为了使用 M_Args_Count 产生的值,且在宏中不以数字开头,现假定最终输出的结果是’M_N’的形式,则 M_Args_N 调整为如下形式:
#define M_Args_N( \
_1, _2, _3, _4, _5, \
N,...) M_##N
测试情况如下:
M_Args_Count() //1
M_Args_Count(int) //1
M_Args_Count(int,int) //2
M_Args_Count(int,int,int) //3
备注:对于无参数的情况不能正确的展开,但是在gcc下可以正常使用,网上有系列宏,可以直接百度到。
推荐链接:
1、c/c++:计算可变参数宏 __VA_ARGS__的参数个数
2、C语言笔记_宏定义系列_获取可变参数宏的参数数量
由于要直接使用最终结果,而不是单纯获取值,通过模板函数获取个数的方法不太适合当前的情况,其中模板型写法如下:
// C++11
template<class... Args>
constexpr size_t args_len(Args&&... args) noexcept
{
return sizeof...(args);
}
#define ARGS_LEN(...) (args_len(__VA_ARGS__))
2.2 调用父类同名函数
//C_BaseClass 基类名称
//P_Return 函数返回值类型
//F_FunName 函数名称
//P_T1 参数1类型名
//p_v1 参数1变量名
#define M_2_ClassImpl(C_BaseClass,P_Return,F_FunName,P_T1,p_v1)\
P_Return F_FunName(P_T1 p_v1){return C_BaseClass::F_FunName(p_v1);}
有几个‘M_’之后就定义为几,且将这个作为后续使用过程中约定。
2.3 提升为public
1、需要对无参数的情况进行特殊处理,如下:
#define M_ClassImpl_Void(C_BaseClass,P_Return,F_FunName)\
P_Return F_FunName(){return C_BaseClass::F_FunName();}
备注:该形式与2.2是同样的,只不过没有参数看起来更简洁
2、统合有参数的函数
//展开
#define M_ClassImpl_Expand(x) x
//自动判断需要'M_N_ClassImpl'中'N'值,本质是一个拼接过程
#define M_ClassImpl_Auto(C_BaseClass,P_Return,F_FunName,...) \
M_ClassImpl_Expand( \
M_Args_Count(__VA_ARGS__)##_ClassImpl( \
C_BaseClass,P_Return,F_FunName,__VA_ARGS__ \
))
备注:直接使用最开始定义的 ‘M_Expand’ 宏似乎也是可以的。
3.使用
常规的使用过程可能如下:
class A
{
protected:
void Get() {}
void Get(int a) {}
void Get(int* a, int b) {}
int Get(const int* a, const double& b) {}
QList<int> Get(int a, int b, int c, int d, int e, int f) {}
};
class B:public A
{
public:
M_ClassImpl_Void(A, void, Get)
M_ClassImpl_Auto(A, void, Get, int, a)
M_ClassImpl_Auto(A, int, Get, const int*, a, const double&, b)
M_ClassImpl_Auto(A, QList<int>, Get, int, a, int, b, int, c, int, d, int, e, int, f)
};
备注:其中A类中有返回值的需要写了实现才能编译通过!
B类中通过类似宏的形式可不比自己写完整的实现,但实际上总共也没有几行,就算是直接写在类内似乎也没有问题。
好像又有了新的想法,在M_ClassImpl_Auto中其实并不用定义参数名,如下:
#define M_2_ClassImpl(C_BaseClass,P_Return,F_FunName,P_T1,P_T2)\
P_Return F_FunName(P_T1 p_v1,P_T2 p_v2){return C_BaseClass::F_FunName(p_v1,p_v2);}
只需要在实现过程中定义出来参数名称即可。
此时的使用过程如下:
class A
{
protected:
void Get() {}
void Get(int a) {}
void Get(int* a, int b) {}
int Get(const int* a, const double& b) {}
QList<int> Get(int a, int b, int c, int d, int e, int f) {}
};
class B:public A
{
public:
M_ClassImpl_Void(A, void, Get)
M_ClassImpl_Auto(A, void, Get, int)
M_ClassImpl_Auto(A, int, Get, const int*, const double&)
M_ClassImpl_Auto(A, QList<int>, Get, int, int, int, int, int, int)
};
4.整体代码
#pragma once
//对于0的判定有问题
#define M_Expand(...) __VA_ARGS__
#define M_Args_N( \
_1, _2, _3, _4, _5, \
_6, _7, _8, _9, _10, \
_11, _12, _13, _14, _15, \
_16, _17, _18, _19, _20, \
_21, _22, _23, _24, _25, \
_26, _27, _28, _29, _30, \
_31, _32, _33, _34, _35, \
_36, _37, _38, _39, _40, \
_41, _42, _43, _44, _45, \
_46, _47, _48, _49, _50, \
_51, _52, _53, _54, _55, \
_56, _57, _58, _59, _60, \
_61, _62, _63, _64, _65, \
_66, _67, _68, _69, _70, \
_71, _72, _73, _74, _75, \
_76, _77, _78, _79, _80, \
_81, _82, _83, _84, _85, \
_86, _87, _88, _89, _90, \
_91, _92, _93, _94, _95, \
_96, _97, _98, _99, _100, \
_101,_102,_103,_104,_105, \
_106,_107,_108,_109,_110, \
N,...) M_##N
#define M_Args_Count(...) \
M_Expand(M_Args_N( \
__VA_ARGS__, \
110,109,108,107,106, \
105,104,103,102,101, \
100,99, 98, 97, 96, \
95, 94, 93, 92, 91, \
90, 89, 88, 87, 86, \
85, 84, 83, 82, 81, \
80, 79, 78, 77, 76, \
75, 74, 73, 72, 71, \
70, 69, 68, 67, 66, \
65, 64, 63, 62, 61, \
60, 59, 58, 57, 56, \
55, 54, 53, 52, 51, \
50, 49, 48, 47, 46, \
45, 44, 43, 42, 41, \
40, 39, 38, 37, 36, \
35, 34, 33, 32, 31, \
30, 29, 28, 27, 26, \
25, 24, 23, 22, 21, \
20, 19, 18, 17, 16, \
15, 14, 13, 12, 11, \
10, 9, 8, 7, 6, \
5, 4, 3, 2, 1 \
))
#define M_ClassImpl_Expand(x) x
#define M_ClassImpl_Auto(C_BaseClass,P_Return,F_FunName,...) \
M_ClassImpl_Expand( \
M_Args_Count(__VA_ARGS__)##_ClassImpl( \
C_BaseClass,P_Return,F_FunName,__VA_ARGS__ \
))
//创建基础函数 [目前先支持到10个参数]
#define M_ClassImpl_Void(C_BaseClass,P_Return,F_FunName)\
P_Return F_FunName(){return C_BaseClass::F_FunName();}
#define M_1_ClassImpl(C_BaseClass,P_Return,F_FunName,P_T1)\
P_Return F_FunName(P_T1 p_v1){return C_BaseClass::F_FunName(p_v1);}
#define M_2_ClassImpl(C_BaseClass,P_Return,F_FunName,P_T1,P_T2)\
P_Return F_FunName(P_T1 p_v1,P_T2 p_v2){return C_BaseClass::F_FunName(p_v1,p_v2);}
#define M_3_ClassImpl(C_BaseClass,P_Return,F_FunName,P_T1,P_T2,P_T3)\
P_Return F_FunName(P_T1 p_v1,P_T2 p_v2,P_T3 p_v3){return C_BaseClass::F_FunName(p_v1,p_v2,p_v3);}
#define M_4_ClassImpl(C_BaseClass,P_Return,F_FunName,P_T1,P_T2,P_T3,P_T4)\
P_Return F_FunName(P_T1 p_v1,P_T2 p_v2,P_T3 p_v3,P_T4 p_v4){return C_BaseClass::F_FunName(p_v1,p_v2,p_v3,p_v4);}
#define M_5_ClassImpl(C_BaseClass,P_Return,F_FunName,P_T1,P_T2,P_T3,P_T4,P_T5)\
P_Return F_FunName(P_T1 p_v1,P_T2 p_v2,P_T3 p_v3,P_T4 p_v4,P_T5 p_v5){return C_BaseClass::F_FunName(p_v1,p_v2,p_v3,p_v4,p_v5);}
#define M_6_ClassImpl(C_BaseClass,P_Return,F_FunName,P_T1,P_T2,P_T3,P_T4,P_T5,P_T6)\
P_Return F_FunName(P_T1 p_v1,P_T2 p_v2,P_T3 p_v3,P_T4 p_v4,P_T5 p_v5,P_T6 p_v6){return C_BaseClass::F_FunName(p_v1,p_v2,p_v3,p_v4,p_v5,p_v6);}
#define M_7_ClassImpl(C_BaseClass,P_Return,F_FunName,P_T1,P_T2,P_T3,P_T4,P_T5,P_T6,P_T7)\
P_Return F_FunName(P_T1 p_v1,P_T2 p_v2,P_T3 p_v3,P_T4 p_v4,P_T5 p_v5,P_T6 p_v6,P_T7 p_v7){return C_BaseClass::F_FunName(p_v1,p_v2,p_v3,p_v4,p_v5,p_v6,p_v7);}
#define M_8_ClassImpl(C_BaseClass,P_Return,F_FunName,P_T1,P_T2,P_T3,P_T4,P_T5,P_T6,P_T7,P_T8)\
P_Return F_FunName(P_T1 p_v1,P_T2 p_v2,P_T3 p_v3,P_T4 p_v4,P_T5 p_v5,P_T6 p_v6,P_T7 p_v7,P_T8 p_v8){return C_BaseClass::F_FunName(p_v1,p_v2,p_v3,p_v4,p_v5,p_v6,p_v7,p_v8);}
#define M_9_ClassImpl(C_BaseClass,P_Return,F_FunName,P_T1,P_T2,P_T3,P_T4,P_T5,P_T6,P_T7,P_T8,P_T9)\
P_Return F_FunName(P_T1 p_v1,P_T2 p_v2,P_T3 p_v3,P_T4 p_v4,P_T5 p_v5,P_T6 p_v6,P_T7 p_v7,P_T8 p_v8,P_T9 p_v9){return C_BaseClass::F_FunName(p_v1,p_v2,p_v3,p_v4,p_v5,p_v6,p_v7,p_v8,p_v9);}
#define M_10_ClassImpl(C_BaseClass,P_Return,F_FunName,P_T1,P_T2,P_T3,P_T4,P_T5,P_T6,P_T7,P_T8,P_T9,P_T10)\
P_Return F_FunName(P_T1 p_v1,P_T2 p_v2,P_T3 p_v3,P_T4 p_v4,P_T5 p_v5,P_T6 p_v6,P_T7 p_v7,P_T8 p_v8,P_T9 p_v9,P_T10 p_v10){return C_BaseClass::F_FunName(p_v1,p_v2,p_v3,p_v4,p_v5,p_v6,p_v7,p_v8,p_v9,p_v10);}
//C++11
template<class... Args>
constexpr size_t args_len(Args&&... args)noexcept
{
return sizeof...(args);
}
#define ARGS_LEN(...) (args_len(__VA_ARGS__))