会产生编译错误:return type ‘class B’ is incomplete
a.h,A类是一个模板类:
#ifndef A_H
#define A_H
#include "b.h"
class B;
template <typename T>
class A
{
public:
A(){}
B print();
};
template <typename T>
B A<T>::print()
{
B b;
return b;
}
#endif // A_H
b.h
#ifndef B_H
#define B_H
#include "a.h"
class B
{
public:
B();
A<B> get();
};
#endif // B_H
b.cpp:
#include "b.h"
B::B()
{
}
A<B> B::get()
{
return A<B>();
}
A通过print函数可以返回一个B的对象,B通过get函数可以获得A< B > 的对象。如何才能不报错?
在完整地定义一个类之前,即使有声明,也只能用指针或引用。
模板类的事情先放一边,你这样两个文件相互调用的写法是错误的,根本就是不允许这么写,自然无法编译通过,你要么让B引用A类的文件,要让A引用B类的问题,其他的行为都是错误的。
a.h文件中的class B;改成extern class B;
#ifndef A_H
#define A_H
#include "b.h"
class B;
template <typename T>
class A
{
public:
A() {}
B* print();
};
template <typename T>
B* A<T>::print()
{
B* b;
return b;
}
我现在的项目也常遇到互相包含、互相引用之类的问题,目前基本上要通过使用指针解决,上述代码改成B类指针可以正常编译使用。不过需要注意以下几点:
①引入指针之后的类,一定要有构造函数,尤其是拷贝构造函数,而且必须是深拷贝为指针对象分配内存,因为编译器默认给的是浅拷贝,不处理内存拷贝,只拷贝了指针,后续的指针使用在常见的对象传参情形下非常容易出现数据异常;
②引入指针之后的类,一定要有析构函数,在析构函数中统一处理构造函数动态分配的内存,并且声明为虚函数,以保证可能从该类继承的类对象释放内存时会调用该类析构函数,彻底释放内存,避免内存泄漏;
③引入指针之后的类,一般来说可以通过shared_ptr智能指针管理动态内存,但是如果指针类的使用跨文件,或者涉及全局类对象,最好自己手动管理分配与释放(自己大型项目中的应用总结);
④引入指针之后的类中的成员函数(除了构造和拷贝构造函数),在清楚后续该类是否会参与继承关系的情况下,要注意加上virtual关键字,方便扩展(多态)
⑤如果明确知道该类会参与继承关系,要注意考虑菱形继承(钻石继承)的情形,继承中如果有两个派生有共同的基类,这俩派生类必须要采用虚继承,以免造成派生类对象数据混乱
C++11——C++17新标准多了很多新特性,可以帮助程序员开发工作更便捷,,Boost库是跨平台的,里面集成了很多非常高效的功能和解决方案,建议开发方案或功能之前先了解以下,避免重复造车。
唠叨完毕,希望帮助到楼主
不是模板类导致的问题,而是在b.cpp 中有代码 {#include "b.h"}, 编译器就会编译b.h而导致编译失败,如下图:
总的来说,编译A类就需要先知道B类(占多少字节),而编译B类也需要先知道A类(占多少字节),很明显这个逻辑是不可能实现的,所以只能打破这个关系。
如:修改A类:**B print();** 改成 B* print(); ,那么在编译A类的时候就不需要知道B类占多少字节,因为编译器知道B* 是指针类型,占4个字节(32位系统),然后就可以去掉A.h的代码“#include "b.h" ”,编译器就能顺利编译了。