C++不完整的类型

今天写C++primer 5th中文版第422页的程序时,出现了”不允许使用不完整的类型“的错误,下面我就用类A 与 类B 作为代表,重现一下该错误,并且提出解决方案。

一、带问题的类设计A:

1、类A放在A.h 与 A.cpp中

2、由于B需要访问A的私有成员,故声明B是其友元类

3、A中需要利用自身作为参数去创建一个新的B类实例。

代码如下:A.cpp中就是一个空的析构函数的实现。。。没什么,我把主要实现都写在了A.h中

 1 #pragma once
 2 #include<iostream>
 3
 4 class B; // 声明B 从而能够在下文声明为友元类
 5 class A
 6 {
 7 public:
 8     friend class B; // 声明B为友元类
 9     A(int a) :data(a){}
10
11     B Pirnt() // 打印一行文字并且调用B的构造函数:B(A &a, int secParam = 5)创建一个B的实例
12     {
13         std::cout << "hehe " << std::endl;
14         return B(*this);
15     }
16     ~A();
17 private:
18     int data;
19 };

二、带问题的类设计B

1、B 接受一个A 引用参数,达成构造B的目的

同样的,B.cpp中也是一个空的构造函数与一个空的析构函数,下面展示的是B.h中的代码:

 1 #pragma once
 2 #include "A.h"
 3 class B
 4 {
 5 public:
 6     B(A &a, int secParam = 5) :data(a.data){}
 7     B();
 8     ~B();
 9
10 private:
11     int data;
12 };

三、问题提示:

在A.h的第11 与 14行使用B的地方提示”B不是完整的数据类型“

四、分析

首先,我们需要在类A中将B声明为友元类,此时类B尚未定义,故仅在class A前面声明了class B;然后在此利用B进行代码编写,但是带来了问题:

这种声明叫做 前向声明,它在声明之后,定义之前的这段时间,它都是不完整的,对于类A中的代码来讲,他们不知道B什么时候定义,所以编译器直接认为B是不完整的。。。

如果分别在A.h与B.h中包含对方的头文件,又造成了循环包含。

五、解决方案。

1、将A  B写在一个头文件中

2、声明A,定义B

3、定义A

代码:

A.h

#pragma once
#include<iostream>
class A;  // 声明A

class B
{
public:
    B(A &a, int secParam = 5); // 只可声明,不能在此处定义,具体定义在B.cpp中写
    ~B();

private:
    int data;
};

class A
{
public:
    friend class B; // 声明B为友元类
    A(int a) :data(a){}

    B Pirnt() // 打印一行文字并且调用B的构造函数:B(A &a, int secParam = 5)创建一个B的实例
    {
        std::cout << "hehe " << std::endl;
        return B(*this);
    }
    ~A();
private:
    int data;
};

B.cpp

#include "A.h"
B::B(A &a, int secParam) :data(a.data)
{
}

B::~B()
{
}

对于A.cpp,还是空的构造函数与析构函数

原因:

1、上文说道在类声明与定义之间的时间内,其是不完整的,不可使用的,但是  可以定义指向这种类型的指针和引用,可以声明(不能定义)以不完整类型作为参数或者返回类型的函数。

故,可以先在B中的构造函数里使用 A& 这个参数.

不过使用A&作为参数的那个构造函数的实现(定义)需要在cpp中写,因此执行到CPP的时候,A已经是完整的了。

2、 执行到A时,B的各成员声明已经完整。

时间: 2024-07-30 03:14:30

C++不完整的类型的相关文章

如何在C++中获得完整的类型名称

地球人都知道C++里有一个typeid操作符可以用来获取一个类型/表达式的名称: std::cout << typeid(int).name() << std::endl; 但是这个name()的返回值是取决于编译器的,在vc和gcc中打印出来的结果如下: int // vc i // gcc 一个稍微长一点的类型名称,比如: class Foo {}; std::cout << typeid(Foo*[10]).name() << std::endl; 打

(二)c++入门——你真的是在自学编程吗?——不允许使用不完整的类型=》缺少头文件

今天在使用array中,做如下声明: array<float,3> runRecords; // 一直提示:不允许使用不完整的类型 刚入门c++,对于许多报错,实在搞不懂这是什么意思,翻看书前面的内容,才发现,要使用array类,必须包含头文件#include <array>. 对于array这个知识点,可以确定的是,自己当时是看懂的了.我们大部分成人在自学的过程中,也常常会有这样的错觉:看懂了=学会了.也即是走这样的一个过程(红色箭头): 往往少了图中的第二步:也即没有实际使用来

不允许使用不完整的类型

场景 使用wxPaintDC dc(this);的情况下,出现上述错误 解决 #include "wx/dcclient.h" 原理 需要包含类型的定义,添加相关的头文件

C语言不完全类型与延迟定义

一直以为我的C语言学的还可以,虽说不是出神入化,但是至少比较熟悉吧.但是前一段时间看了一篇微信推文,再百度了一下C语言不完全类型.发现我居然C语言不完全类型和用途甚广的延迟定义都没概念.这两天仔细查阅了相关概念并用代码实验了一下. 本文结构如下: C语言不完全类型概念介绍 一个故事 延迟定义的优点 思考- C语言不完全类型 不完全类型也就是不知道变量的所有的类型信息.比如可以声明一个数组,但是不给出该数组的长度:声明一个指针,但是不给出该指针的类型:声明一个结构体类型,但是不给出完整的结构体定义

Swift 语言附注 类型

本页包含内容: 类型注解(Type Annotation) 类型标识符(Type Identifier) 元组类型(Tuple Type) 函数类型(Function Type) 数组类型(Array Type) 可选类型(Optional Type) 隐式解析可选类型(Implicitly Unwrapped Optional Type) 协议合成类型(Protocol Composition Type) 元类型(Metatype Type) 类型继承子句(Type Inheritance C

iOS开发——switf篇&amp;经典语法(一)类型

类型 Swift 语言存在两种类型:命名型类型和复合型类型.命名型类型是指定义时可以给定名字的类型.命名型类型包括类.结构体.枚举和协议.比如,一个用户定义的类 MyClass的实例拥有类型MyClass.除了用户定义的命名型类型,Swift 标准库也定义了很多常用的命名型类型,包括那些表示数组.字典和可选值的类型. 那些通常被其它语言认为是基本或初级的数据型类型(Data types)——比如表示数字.字符和字符串——实际上就是命名型类型,Swift 标准库是使用结构体定义和实现它们的.因为它

C#实现完整的防盗自制监控系统

在您的手机中通知您家中的入侵者,并拍摄他们的照片 介绍 在本文中,我将展示一些DIY东西??,用于安装监控系统,检测家中的入侵者,拍摄照片并通过手机通知您,必要时可以打电话给警察并提供照片以便快速识别劫匪,并提高你恢复所有被盗事物的机会. 当然,除了这个软件,你必须提供一些硬件,但我已经在我家使用相对便宜的材料建造了这个系统,如果我们除了相机,这是安装中最昂贵的部分.但你可以用相机做很多事情,所以它可以是一个好的和有趣的投资. 基本上,这是系统架构,包含所有参与元素: 虽然在模式中我已经代表了一

C#中类型分析中的常见问题 Type - 转

http://www.cnblogs.com/yuanyuan/archive/2012/08/16/2642281.html 写代码的时候经常需要分析已有类型的信息例如:分析现有类型自动生成类, 或者为现有的类自动增加一些功能总结了一点点经验以ClassA  a; 为例1. 通过typeof(ClassA) 或者 a.GetType() 获取类型信息, 推荐使用typef() 可以避免空引用,而且有的时候不需要构造一个ClassA的实例, typeof(ClassA)的性能一点都不差,不要把它

Spring BeanFactory 中的类型推断

Spring BeanFactory 中的类型推断 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html) Spring 容器中可以根据 beanName 查找其类型,其推断方式和 bean 的创建方式密切相关,并且 Spring 中有一个原则是尽可能的不要通过创建 bean 来获取其类型,除了 FactoryBean 只有通过创建对象调用其 getObjectType 方法,但也只是部分的创建该 FactoryBean(所谓