【问题标题】:Is it ok for 2 classes to have field pointing eachother?2个班级可以互相指向字段吗?
【发布时间】:2017-04-03 17:01:51
【问题描述】:

所以我有课程UserJob

class User {
 string user_name;
 Job* job;
};

class Job {
 string job_type;
 int salary;
 User* user;
};

这种设计有什么问题吗?我有大量的Jobs 和Users,我想快速访问用户的工作或正在工作的用户。这些类的字段相互指向可以吗?

【问题讨论】:

  • 仅供参考,您的示例可能是 begging 用于 std::shared_ptrstd::weak_ptr 的用法,而不是像您一样使用原始指针。单击提供的链接以了解有关它们的更多信息。
  • 我会使用一种完全不同的方法来处理 SQL 数据库和三个表“user”、“job_type”和“job”,后者在其他两个表之间建立关系,这样任何用户都可以拥有 0到 n 个工作。在您的 C++ 代码中,您将不再拥有单独的类 UserJob,而是直接由适当的 JOIN 产生的不可变查询结果类。任何修改都通过或多或少显式的 UPDATE 或 INSERT 进行。我发现这样的架构非常容易使用,正是因为它们让你摆脱了这个精确的指针问题。

标签: c++ class oop pointers class-design


【解决方案1】:

没关系。例如,您需要小心谨慎地管理指针以避免泄漏。但这是完全合理的。

【讨论】:

  • 我投了赞成票,但我更关心悬空指针而不是内存泄漏。如果您担心内存泄漏,这意味着这些指针拥有已动态分配的原始指针,这通常不是一个好主意。
  • 您可以使用智能指针。然后你需要担心可能来自循环引用的泄漏。这就是弱指针的用武之地。stackoverflow.com/questions/12030650/when-is-stdweak-ptr-useful
【解决方案2】:

这是 oop 世界中的常见情况。例如,典型的 GUI 架构以类似的方式使用这种方法,如下所示:

  1. 小部件知道它的父级。它保持指向父级的指针。

  2. 复合小部件知道它的 z 顺序子级(小部件)

我明白,这样的例子与您的帖子相去甚远。它只是显示大小写。

我不知道您的应用程序的确切架构。但也许 Job 类不应该知道用户?它减少了额外的关系并简化了内存管理(而不是用于更好地控制共享指针和弱指针)

【讨论】:

    【解决方案3】:

    只要User 不拥有Job 并且Job 不拥有User 就可以了。

    例如,您可能会预先创建 Jobs 和 Users 的集合,然后想在它们之间创建关联:

    #include <string>
    #include <vector>
    
    class Job;
    
    class User {
        std::string user_name;
        Job* job;
      public:
        explicit User(const std::string& user_name) : user_name(user_name) {}
        void setJob(Job& job) { this->job = &job; }
    };
    
    class Job {
        std::string job_type;
        int salary;
        User* user;
      public:
        Job(const std::string& job_type, int salary) : job_type(job_type), salary(salary) {}
        void setUser(User& user) { this->user = &user; }
    };
    
    void recruit(User& user, Job& job) {
      user.setJob(job);
      job.setUser(user);
    }
    
    int main() {
        auto jobs = std::vector<Job>{ {"Tinker", 10'000}, {"Tailor", 20'000}};
        auto users = std::vector<User> {User{"George"}, User{"Percy"}};
        recruit(users[0], jobs[1]);
        recruit(users[1], jobs[0]);
    }
    

    只要Users 和Jobs 的集合同时被销毁,就没有悬空指针的危险。如果指针是const 指针可能会更好。

    但如果您的意图是某种所有权,那么智能指针将是首选。

    【讨论】:

      【解决方案4】:

      我有点惊讶大多数答案都表明这种设计还可以。

      除非有充分的理由(如性能要求)这样做,否则我认为这是不可接受的。

      这是一种循环依赖,会损害代码的可读性和可测试性。但我主要担心的是很难保持引用的一致性。

      作为替代方案,我将只提供一个参考,例如 User 有一个指向 Job 的指针。现在,如果您有一个 Job 并且想要找到相应的 User(s),您仍然可以搜索所有用户并找到具有指向该 Job 的指针的那些。当然,这比直接指针效率低,但在许多情况下它并不重要。可能更重要的是不能出现不一致。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-21
        • 2022-09-27
        • 1970-01-01
        相关资源
        最近更新 更多