C++ 循环引用和解决办法

时间:2024-06-01 21:22:37

目录

智能指针的循环引用问题

weak_ptr解决循环引用问题

类的循环依赖问题

智能指针解决类的循环引用问题

头文件 A.h

头文件 B.h

源文件 main.cpp

前向声明例子;

源文件 main.cpp

2、抽象出父类,A,B作为派生类


智能指针的循环引用问题

weak_ptr解决循环引用问题

C++中的各种循环依赖和解决办法_c++ 循环依赖-****博客

类的循环依赖问题

在C++中,类的循环引用问题通常出现在两个或多个类互相包含对方的指针或引用,从而导致编译错误或内存管理问题。解决循环引用的常见方法包括使用前向声明(forward declaration)和智能指针(如std::shared_ptrstd::weak_ptr)。以下是一个示例,演示如何使用前向声明和智能指针来解决类的循环引用问题:

智能指针解决类的循环引用问题

头文件 A.h
#ifndef A_H
#define A_H

#include <memory>

// 前向声明类B
class B;

class A {
public:
    A() : b_ptr(nullptr) {}
    void setB(std::shared_ptr<B> b) { b_ptr = b; }
private:
    std::shared_ptr<B> b_ptr;
};

#endif // A_H
头文件 B.h
#ifndef B_H
#define B_H

#include <memory>
#include "A.h"

class B {
public:
    B() : a_ptr(nullptr) {}
    void setA(std::shared_ptr<A> a) { a_ptr = a; }
private:
    std::shared_ptr<A> a_ptr;
};

#endif // B_H
源文件 main.cpp
#include <iostream>
#include "A.h"
#include "B.h"

int main() {
    std::shared_ptr<A> a = std::make_shared<A>();
    std::shared_ptr<B> b = std::make_shared<B>();

    a->setB(b);
    b->setA(a);

    std::cout << "Circular reference resolved using shared_ptr and weak_ptr" << std::endl;

    return 0;
}

前向声明例子;

头文件 A.h

#ifndef A_H
#define A_H

// 前向声明类B
class B;

class A {
public:
    A() : b_ptr(nullptr) {}
    void setB(B* b) { b_ptr = b; }
    void print();
private:
    B* b_ptr;
};

#endif // A_H

头文件 B.h

#ifndef B_H
#define B_H

#include "A.h"

class B {
public:
    B() : a_ptr(nullptr) {}
    void setA(A* a) { a_ptr = a; }
    void print();
private:
    A* a_ptr;
};

#endif // B_H

源文件 A.cpp

#include <iostream>
#include "A.h"
#include "B.h"

void A::print() {
    std::cout << "A is printing" << std::endl;
    if (b_ptr) {
        b_ptr->print();
    }
}

源文件 B.cpp

#include <iostream>
#include "B.h"

void B::print() {
    std::cout << "B is printing" << std::endl;
    if (a_ptr) {
        a_ptr->print();
    }
}

源文件 main.cpp

#include "A.h"
#include "B.h"

int main() {
    A a;
    B b;

    a.setB(&b);
    b.setA(&a);

    a.print();

    return 0;
}

2、抽象出父类,A,B作为派生类


用指针替代变量声明的方法虽然能够编译通过,但是存在一个问题,就是无法进行单元测试。测A需要B是完整的,B又依赖A,那A到底要怎么测试。为了能够进行单元测试,可以考虑将方法和数据抽出作为父类。

class Base {   
 public:    
     int fun1();
     int fun2();
 };
 
class A {
public:
int funA() { return fun1(); };

class B {
public:
int funB() { return fun2(); };
};