通过宏将父类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__))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值