1. 使用场景
类的实现中需要使用其他类的某个函数时,通常可以采用实例对象的方法,但是当两个类依赖很深,互相关联的时候的,这么操作往往不尽人意。
例如:类A中某函数用到类B的实例对象,而类B又需要A的某个函数,但是A和B都用到了一个全局变量,且A初始化用到了该变量。现在解决B需要A函数的问题。
如果B中创建A的对象实例,那么就会初始化改变全局变量的值,所以用这种方法会导致错误,我们不希望全局变量再次被初始化。
如下:
类A初始化了全局变量str,类A中创建了B的对象,B的对象修改了str。
此时B的useA()函数需要使用A的hello()函数,如果是直接用A的对象
void B::useA(){
std::cout<<"B调用了A的函数:";
//((A*)ptr)->hello();
A tempA;
tempA.hello();
}
那么输出结果为:
可以看到A重新初试化了str,而我们想要保留B修改str的结果,这种用法显然存在错误。
所以现在还有一种思路:==B通过一个强转的A类指针,来调用A中的函数==。
2. 测试代码
A.h
#ifndef A_H
#define A_H
#include<string>
using namespace std;
class A
{
public:
A();
void hello();
void createB();
void changeStr();
};
#endif
A.cpp
#include "A.h"
#include "B.h"
#include<iostream>
extern string str;
A::A(){
std::cout<<"创建了一个A对象\n\n";
str="A初始化str";
std::cout<<str<<"\n\n";
}
void A::createB(){
std::cout<<"调用A的createB函数,创造一个B对象\n\n";
B tempB;
tempB.useA();
}
void A::hello(){
std::cout<<"A的hello函数,现在str为:"<<str;
}
B.h
#ifndef B_H
#define B_H
class B
{
public:
B();
void useA();
void *ptr;
};
#endif
B.cpp
#include "B.h"
#include "A.h"
#include<iostream>
extern string str;
B::B(){
std::cout<<"B类的构造函数," ;
extern string str;
str="B修改了str";
std::cout<<str<<"\n\n";
}
void B::useA(){
std::cout<<"B调用了A的函数:";
((A*)ptr)->hello();
}码片
main.cpp
#include<iostream>
#include "a.h"
using namespace std;
string str;
int main(){
A a;
a.createB();
return 0;
}
和刚才不同的是,这次把useA换成了
((A*)ptr)->hello();
首先在B中定义了一个void *ptr的空指针,然后强转成A* 去调用A的函数hello()
此时结果正确:
3.缺点
不过据我使用来看,这种方法也有一定的副作用,
例如运用到QT中去调用其他类的函数,只能调用一些和对象实例化关系不大的函数。如果函数中有必须创建对象的部分,比如QT中的视图必须绑定对象,那么该方法调用虽然可以通过编译,但是运行会产生崩溃。因为强转的空指针调用的时候没有指向的对象,编译器找不到运行时会crash,但是编译的时候是符合逻辑的。这可能会带来巨大的隐患。
4.改进
通过我的摸索,我觉得可以用全局变量的方法解决这种隐患,例如上述例子,在主函数中将A作为全局变量
A *a;
int main(){
a=new A;
a->createB();
return 0;
}
useA函数作如下修改
void B::useA(){
std::cout<<"B调用了A的函数:";
extern A *a;
a->hello();
}
结果依然正确
另外一个相关的QT编程问题,有兴趣可以看看我的另一篇博客,也是同样的方法:
https://blog.csdn.net/qq_51681065/article/details/128793426
各位网友,我的C++水平很低,这种方法只是分享。如果大家有其他想法,或者有开发经验的同志愿意分享这种问题的处理经验,非常欢迎!