共享通用代码而不使用friend并忽略包含依赖项

发布于 2025-01-09 09:11:40 字数 3937 浏览 3 评论 0原文

我的问题:

有没有更好的方法来做宏扩展之类的事情。感觉就像把代码放在同一个文件中,单独工作而不使用 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 需要被 AB 继承

#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.

Live demo

#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 ===:

Live demo


#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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文