共享通用代码而不使用friend并忽略包含依赖项
我的问题:
有没有更好的方法来做宏扩展之类的事情。感觉就像把代码放在同一个文件中,单独工作而不使用 friend
并且不破坏封装?
详细信息:
我有两节课。两个类具有完全相同的功能,执行相同的工作,并且它们的源文件中具有重复的代码。然而他们没有共同的基类。
class A{
public:
void run(){
// In real code it has dependency to 10+ headers below. Just use vector as an example
std::vector<int> v;
v.push_back(0); // Something more complex here.
instance.enable();
}
protected:
void enable(){
std::cout<< "A enable" << std::endl;
}
};
class B{ //Same as A, but B and A have no common class.
};
我尝试进行重构,将代码集中到一个文件中,同时不涉及太多内容。我尝试不使用正常的继承方式来处理它,因为我不想再次处理包含标头,因为有很多标头。
使用这种方式,我重构的 Common.h 标头不需要处理包含依赖项,因为模板只需将代码复制/粘贴到两个不同的类中。 以下是我的结果,但我不喜欢朋友
。
旁注:我知道我可以使用像这个片段这样的继承,但我想知道是否还有其他方法来做到这一点。 在我的生产代码中,我使用继承来处理重构,因为并非团队中的所有人都很好地了解模板(我也不是)。
为了简洁起见,我下面的例子中,我删除了 class B
因为它是 class A
的重复
==== CRTP (Mixins like style) ====
这是最重要的我尝试过的最近的方法。
现场演示 注意:使用这种方式,需要处理 header 中的依赖关系,因为 Common
需要被 A
和 B
继承
#include <iostream>
#include <string>
// Common.h
#include <vector>
template<typename T>
class Common {
public:
virtual void runImpl(){
enable();
// In real code it has dependency to 10+ headers below. Just use vector as an example
std::vector<int> v;
v.push_back(0);
}
protected:
virtual void enable() = 0;
};
class A: public Common<A>{
public:
void run(){
runImpl();
}
protected:
void enable(){
std::cout<< "A enable" << std::endl;
}
};
int main(){
A a;
a.run();
return 0;
}
==== Another通过 std::fucntion
重构====
通过删除友元,我对 std::funciton
使用依赖注入。然而这种方式会导致重构对运行时的性能产生影响。我可以使用它,因为它只是一个简单的 GUI 任务。
#include <iostream>
#include <functional>
// Common.h
#include <vector>
namespace Common{
void runImpl(std::function<void()> enableFunction){
// In real code it has dependency to 10+ headers below. Just use vector as an example
std::vector<int> v;
v.push_back(0); // Something more complex here.
enableFunction();
}
}
// A.h + A.cpp
class A{
public:
void run(){
auto enableFunc = std::bind(&A::enable, this);
Common::runImpl(enableFunc);
}
protected:
void enable(){
std::cout<< "A enable" << std::endl;
}
};
int main(){
A a;
a.run();
return 0;
}
=== 与 friend
一起重构 ===:
#include <iostream>
// Forward declaration
namespace Common{
template<class T>
void freerun(T& instance);
}
// A.h + A.cpp
class A{
public:
template<class T>
friend void Common::freerun(T& instance);
void run(){
Common::freerun(*this);
}
protected:
void enable(){
std::cout<< "A enable" << std::endl;
}
};
// Common.h
#include <vector>
namespace Common{
template<class T>
void freerun(T& instance){
// In real code it has dependency to 10+ headers below. Just use vector as an example
std::vector<int> v;
v.push_back(0); // Something more complex here.
instance.enable();
}
}
int main(){
A a;
a.run();
return 0;
}
My question:
Is there any better way to do something like macro expansion. It feels like putting the code in the same file and working separately without using friend
and not breaking encapsulation?
Details:
I have two class. Two classes have exact the same function doing the same work and they have duplicate code in their source file. However they don't have common base class.
class A{
public:
void run(){
// In real code it has dependency to 10+ headers below. Just use vector as an example
std::vector<int> v;
v.push_back(0); // Something more complex here.
instance.enable();
}
protected:
void enable(){
std::cout<< "A enable" << std::endl;
}
};
class B{ //Same as A, but B and A have no common class.
};
I tried to refactor to pull the code together in one file while not touching much things. I tried not to use normal inheritance way to handle it, because I don't want to handle the include headers again since there are many headers.
Using this way, my refactored Common.h
header doesn't need to take care of include dependencies since template would just copy/paste the code into two different classes.
Following is my result, but I don't like friend
.
Side note: I know I could use inheritance like this snippet, but I want to discover if there is other ways to do it.
In my production code, I use inheritance to handle the refactor since not all people in my teams knows template well (neither do I).
For the brevity of my following examples, I remove class B
since it's duplicate of class A
==== CRTP (Mixins like style) ====
This is the most nearest way I tried.
Live Demo
Note: By using this way, it needs to handle dependencies in header since Common
need to be inherited by A
and B
#include <iostream>
#include <string>
// Common.h
#include <vector>
template<typename T>
class Common {
public:
virtual void runImpl(){
enable();
// In real code it has dependency to 10+ headers below. Just use vector as an example
std::vector<int> v;
v.push_back(0);
}
protected:
virtual void enable() = 0;
};
class A: public Common<A>{
public:
void run(){
runImpl();
}
protected:
void enable(){
std::cout<< "A enable" << std::endl;
}
};
int main(){
A a;
a.run();
return 0;
}
==== Another refactor by std::fucntion
====
By removing the friend, I use dependency injection for std::funciton
. However this way will cause the refactor has performance impact on runtime. I could use it because it's just a simple gui task.
#include <iostream>
#include <functional>
// Common.h
#include <vector>
namespace Common{
void runImpl(std::function<void()> enableFunction){
// In real code it has dependency to 10+ headers below. Just use vector as an example
std::vector<int> v;
v.push_back(0); // Something more complex here.
enableFunction();
}
}
// A.h + A.cpp
class A{
public:
void run(){
auto enableFunc = std::bind(&A::enable, this);
Common::runImpl(enableFunc);
}
protected:
void enable(){
std::cout<< "A enable" << std::endl;
}
};
int main(){
A a;
a.run();
return 0;
}
=== Refactor with friend
===:
#include <iostream>
// Forward declaration
namespace Common{
template<class T>
void freerun(T& instance);
}
// A.h + A.cpp
class A{
public:
template<class T>
friend void Common::freerun(T& instance);
void run(){
Common::freerun(*this);
}
protected:
void enable(){
std::cout<< "A enable" << std::endl;
}
};
// Common.h
#include <vector>
namespace Common{
template<class T>
void freerun(T& instance){
// In real code it has dependency to 10+ headers below. Just use vector as an example
std::vector<int> v;
v.push_back(0); // Something more complex here.
instance.enable();
}
}
int main(){
A a;
a.run();
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论