循环引用的问题

Problems with circular reference

本文关键字:问题 引用 循环      更新时间:2023-10-16

假设我们有一个名为TestAPI的类和一个名为UserAPI的类。将创建类 UserAPI 的对象并将其包含在类 TestAPI 的标头中。

现在,对象UserAPI的实例必须有权访问TestAPI实例的私有成员变量,但这不起作用,因为没有创建特定的对象。我希望我的库的用户在他们的代码(TestAPI)中创建一个对象,以便稍后创建此对象。

例:

main.cpp
{
    TestAPI test;
    test.User.SomeExampleToChangeRequest(); 
}
class TestAPI
{
    friend class UserAPI;
    public:
        UserAPI User;
    private:
        HINTERNET _hRequest;    // Variable which needs to be accessed from User    
};

现在是来自类 UserAPI 的方法来更改请求句柄

UserAPI::SomeExampleToChangeRequest ()
{
    // how do I access _hRequest now? 
    // TestAPI._hRequest will not work since it's not static and class "global"
}

我该如何执行此操作?将其定义为朋友仅适用于访问权限,并不能解决我的问题。

在理解C++面向对象设计方面,有两个主要的改进领域。

  • 提供对私有成员的访问权限的首选应该是公共方法,而不是friend
  • 若要访问方法中其他类型的对象,应传递该类型的对象。不要开始考虑静态或全局对象,除非这是你真正想要的。

我在下面发布了一些代码片段。将它们放在一起来解决您的问题。

class TestAPI {
public:
    // method to modify _hRequest
    void set_hRequest(HINTERNET& in_hRequest) {
        _hRequest = in_hRequest;
    }
    // method to access _hRequest
    HINTERNET& get_hRequest() {
        return _hRequest;
    }
private:
    HINTERNET _hRequest;
};

.

UserAPI::SomeExampleToChangeRequest(TestAPI& t) {
    // use 't' to access TestAPI here, like so ...
    HINTERNET h = t.get_hRequest();  
}

用户创建 TestAPI 对象后,让他们通过引用 UserAPI::SomeExampleToChangeRequest() 方法将其传递。此外,使用 gbjbaanb 提到的前向声明来帮助编译器。

我认为解释

为什么这不可能开箱即用的更清晰的方法是,UserAPI 的每个实例都不知道它是在哪里创建的或它的用途。

老实说,在这里使用这种直接链接,您可能需要在构造UserAPI以允许其调用_hRequest方法时为其提供某种"父"TestAPI指针/引用。

编辑:

基本上将用户API的定义更改为以下内容:

// Forward declaration
class TestAPI;
class UserAPI
{
public:
    UserAPI( TestAPI* inParent )
    : m_parent ( inParent )
    {}
private:
    // Let's make this private to force construction with a TestAPI parent
    UserAPI(){}
    TestAPI* m_parent;
};

请注意前向声明,因为编译器需要知道它的存在。如果您使用的是头文件,请将此声明放在 userAPI.h 的顶部,并且仅在 userAPI.cpp 中包含 testAPI.h。

请记住,这不允许你从userAPI.h中调用任何TestAPI函数,但它会在userAPI中提供完全访问权限.cpp

因此,需要在

userAPI中定义UserAPI::SomeExampleToChangeRequest.cpp

UserAPI::SomeExampleToChangeRequest ()
{
    // The TestAPI variable or function can now be accessed like so
    m_parent->_hRequest;
}

最后一点:如果您不想使用单独的头文件和 cpp 文件,那么只要您在定义 TestAPI 之后定义UserAPI::SomeExampleToChangeRequest那么您就可以开始了。

最后说明:正如 Happy 所提到的,朋友并不是真正需要的,应该在面向对象C++中谨慎使用。最好创建一个公共函数来访问该参数

您可以创建一个前向声明,这是一种表示"稍后将提供此定义"的方法,以便您的代码将正确检查语法,编译器稍后将为您整理内容(它知道这两个类的完整定义)。

但是,存在局限性。由于编译器对前向声明的类一无所知,因此无法引用其方法或大小。这意味着您几乎必须通过指针来引用它,您希望将其包装在智能指针中。