首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

C++:声明对象时“不允许类型不完整”-原因是什么?

C++中声明对象时不允许类型不完整的原因是,C++是一种静态类型语言,编译器在编译阶段需要确定对象的大小和内存布局。如果声明一个不完整的类型,编译器无法确定该类型的大小,从而无法为其分配内存空间。

具体来说,C++要求在使用一个类型之前必须先声明该类型,这是为了确保编译器能够正确地分配内存和处理对象的成员。如果在声明对象时使用了一个不完整的类型,编译器无法确定该类型的大小,因此无法为对象分配足够的内存空间。

不完整的类型通常指的是只有声明而没有定义的类型,比如只有类的前向声明而没有完整的类定义。这种情况下,编译器无法确定类的成员变量和成员函数的大小和布局,因此无法为对象分配正确的内存空间。

为了解决这个问题,可以使用指针或引用来声明对象,因为指针和引用的大小是固定的,不依赖于类型的完整定义。在使用指针或引用声明对象时,编译器只需要知道指针或引用的大小即可,而不需要知道指向的类型的完整定义。

总结起来,C++中声明对象时不允许类型不完整是因为编译器需要确定对象的大小和内存布局,而不完整的类型无法提供这些信息。为了解决这个问题,可以使用指针或引用来声明对象。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

flexible array柔性数组、不定长的数据结构Struct详解

先修知识 不完整类型 在C/C++中对于不完整类型的定义是这样的: 不完整类型是一种缺乏足够的信息去描述一个完整对象类型 还是以数组的定义/声明为例子。...t.p的地址就是(&t + 0x8),0×8这个偏移地址就是成员p在编译就被编译器给hard code了的地址。 总结:不管结构体的实例是什么,访问其成员就是实例的地址加上成员偏移量。...折磨程序员的来了,我们在析构对象,需要显式地在析构函数里面对指针p引用的内存进行释放,不然会出现内存泄露的情况。 那么柔性数组是怎么做到的呢?...符合这个条件的应该是一个非对象的符号地址。 回忆一下上文所说的不完整类型,起始就是一个符号地址。在结构体的尾部放一个长度为0的方案似乎不错,但是C/C++标准规定是不能定义长度为0的数组。标准不允许?...int a[] = {10, 20}; 看到这个声明语句,我们发现a[]其实就是个数组记号,不完整类型,由于赋值语句,所以在编译便确定了数组的大小,是一个完整的数组类型

1.5K20
  • C++】类和对象(下):再探构造函数、类型转换、static成员、友元、内部类、匿名对象、拷贝对象编译器的优化

    我们有成员变量的声明对象的定义,那成员变量在哪里定义?就在初始化列表。 const成员变量,引用成员变量,没有默认构造的类类型变量,必须在初始化列表位置进行初始化,否则会编译报错。...,_month(month) ,_day(day + 1) ,_n(1) ,_ref(num) ,_t(1) //_t走初始化列表 {} 所以当类类型变量有默认构造函数...我们之前说过类型转换会产生一个临时对象。 但是编译器遇到连续构造+拷贝构造,会优化为直接构造。 再拿栈的Push举例。...有名对象的生命周期当前这个作用域。 7.对象拷贝的编译器优化  • 现代编译器会为了尽可能提高程序的效率,在不影响正确性的情况下会尽可能减少一些传参和传参过程中可以省略的拷贝。...• 如何优化C++标准并没有严格规定,各个编译器会根据情况自行处理。

    8710

    c++中两个类互相引用的问题

    最近在改一个C++程序的时候碰到一条警告信息,警告信息为:“                 删除指向不完整“Q2DTorusNode”类型的指针;没有调用析构函数                ...原因分析:         因为class A中B的声明依赖于class B的前置声明,而不是#include "B.H",所以B的定义对A来说不可见,所以无法调用析构函数,导致内存泄露。...A,B,此时必定存在一个对象的定义对于另外一个对象的定义不可见,所以定义失败。...然而前置声明不能定义对象。 解决方案: 此种状况的解决利用前置声明定义的那个类中的保持另外一个类的引用定义为指针,定义指针不需要对那个类的定义可见。...“warning C4150: 删除指向不完整“B”类型的指针;没有调用析构函数”       而且另外的一个问题是在该.h文件中不能使用该指针调用这个类的成员,原因也是定义不可见。

    1.3K20

    c++中两个类互相引用的问题

    最近在改一个C++程序的时候碰到一条警告信息,警告信息为:“                 删除指向不完整“Q2DTorusNode”类型的指针;没有调用析构函数                ...原因分析:         因为class A中B的声明依赖于class B的前置声明,而不是#include "B.H",所以B的定义对A来说不可见,所以无法调用析构函数,导致内存泄露。...A,B,此时必定存在一个对象的定义对于另外一个对象的定义不可见,所以定义失败。...然而前置声明不能定义对象。 解决方案: 此种状况的解决利用前置声明定义的那个类中的保持另外一个类的引用定义为指针,定义指针不需要对那个类的定义可见。...“warning C4150: 删除指向不完整“B”类型的指针;没有调用析构函数”       而且另外的一个问题是在该.h文件中不能使用该指针调用这个类的成员,原因也是定义不可见。

    1.2K20

    c++中两个类互相引用的问题

    最近在改一个C++程序的时候碰到一条警告信息,警告信息为:“                 删除指向不完整“Q2DTorusNode”类型的指针;没有调用析构函数                ...原因分析:         因为class A中B的声明依赖于class B的前置声明,而不是#include "B.H",所以B的定义对A来说不可见,所以无法调用析构函数,导致内存泄露。...A,B,此时必定存在一个对象的定义对于另外一个对象的定义不可见,所以定义失败。...然而前置声明不能定义对象。 解决方案: 此种状况的解决利用前置声明定义的那个类中的保持另外一个类的引用定义为指针,定义指针不需要对那个类的定义可见。...“warning C4150: 删除指向不完整“B”类型的指针;没有调用析构函数”       而且另外的一个问题是在该.h文件中不能使用该指针调用这个类的成员,原因也是定义不可见。

    1.9K50

    c++】异常

    (这里的处理类似 于函数的传值返回) 4. catch(...)可以捕获任意类型的异常,问题是不知道异常错误是什么。所以应该放在模块的最后面 5....throw; //异常对象没有改变 } 3.3捕获所有异常的处理代码 有时我们希望不论抛出的异常是什么类型,程序都可以捕获它们,以防止throw语句在程序中“乱跑...3.4异常安全 构造函数完成对象的构造和初始化,最好不要在构造函数中抛出异常,否则可能导致对象不完整或没有完全初始化 析构函数主要完成资源的清理,最好不要在析构函数内抛出异常,否则可能导致资源泄漏(内存泄漏...,则派生类中可以允许抛出也可以不允许。  ...c++异常的缺点 1. 异常会导致程序的执行流乱跳,并且非常的混乱,并且是运行时出错抛异常就会乱跳。这会导致我们跟踪调试以及分析程序时,比较困难。 2. 异常会有一些性能的开销。

    17310

    extern关键字

    extern是什么及其作用  extern是c++引入的一个关键字,它可以应用于一个全局变量,函数或模板声明,说明该符号具有外部链接(external linkage)属性。...变量的声明指向程序表名变量的类型和名字,即使得名字为程序所知,一个文件如果想使用别处定义的名字则必须包含对那个名字的声明。...具有该属性的类型有,const对象,constexpr对象,命令空间内的静态对象(static objects in namespace scope)none,在类中、函数体和代码块中声明的变量默认是具有...这里强调全局且非常量的原因是,全局非常量的变量默认是外部链接的。...原因是,C++语言在编译的时候为了解决函数的多态问题,会将函数名和参数联合起来生成一个中间的函数名称,而C语言则不会,因此会造成链接无法找到对应函数的情况,此时C函数就需要用extern “C”进行链接指定

    2.5K30

    Java编程思想精粹(九)-接口

    最好能在编译捕捉问题。 1.1 抽象方法 Java 提供了一个叫做抽象方法的机制,这个方法是不完整的:它只有声明没有方法体。包含抽象方法的类叫做抽象类。...如果一个抽象类是不完整的,当试图创建这个类的对象,Java 会怎么做呢?它不会创建抽象类的对象,所以我们只会得到编译器的错误信息。这样保证了抽象类的纯粹性,我们不用担心误用它。...否则,它们只有包访问权限,这样在继承,它们的可访问权限就被降低了,这是 Java 编译器所不允许的。...2.2 多继承 一个类可能从多个父类型中继承特征和特性。 Java 在设计之初,C++ 的多继承机制饱受诟病。...使用接口的核心原因之一:为了能够向上转型为多个基类型(以及由此带来的灵活性)。 然而,使用接口的第二个原因与使用抽象基类相同:防止客户端程序员创建这个类的对象,确保这仅仅只是一个接口。

    51921

    Java编程思想精粹(On Java8)(十)-接口

    最好能在编译捕捉问题。 1.1 抽象方法 Java 提供了一个叫做抽象方法的机制,这个方法是不完整的:它只有声明没有方法体。包含抽象方法的类叫做抽象类。...如果一个抽象类是不完整的,当试图创建这个类的对象,Java 会怎么做呢?它不会创建抽象类的对象,所以我们只会得到编译器的错误信息。这样保证了抽象类的纯粹性,我们不用担心误用它。...否则,它们只有包访问权限,这样在继承,它们的可访问权限就被降低了,这是 Java 编译器所不允许的。...1.2 多继承 一个类可能从多个父类型中继承特征和特性。 Java 在设计之初,C++ 的多继承机制饱受诟病。...使用接口的核心原因之一:为了能够向上转型为多个基类型(以及由此带来的灵活性)。 然而,使用接口的第二个原因与使用抽象基类相同:防止客户端程序员创建这个类的对象,确保这仅仅只是一个接口。

    43220

    CC++刁钻问题各个击破之细说sizeof

    (5)sizeof不能对不完整的数组求长度; (6)当表达式作为sizeof的操作数,它返回表达式的计算结果的类型大小,但是它不对表达式求值!...概述: Sizeof是C/C++中的关键字,它是一个运算符,其作用是取得一个对象(数据类型或者数据对象)的长度(即占用内存的大小,以byte为单位)。...原因是在函数参数传递,数组被转化成指针了,或许你要问为什么要转化成指针,原因可以在很多书上找到,我简单说一下:假如直接传递整个数组的话,那么必然涉及到数组元素的拷贝(实参到形参的拷贝),当数组非常大...原因就是sizeof(arrayA)试图求不完整数组的大小。这里的不完整的数组是指数组大小没有确定的数组!...可是当我去验证,编译器根本不让我通过!这个是为什么呢?我一半会想不到,所以还请朋友们补充! 特性8:sizeof求得的结构体(及其对象)的大小并不等于各个数据成员对象的大小之和!

    88420

    C++ Primer Plus 第02章 开始学习C++ 学习笔记

    ⚠️注意:C++程序通常是以main()函数开始执行,如果没有,程序不完整,则编译器会指出未定义main()函数。 大小写都必须准确 不需要main()函数的特殊情况: 1....<<endl; return 0; } 2.1 声明语句和变量 在C++中,首次使用变量,必须声明 。可以避免因拼写错误而难以发现错误。...声明通常指出要存储的数据类型和程序对存储在内存里的数据使用的名称。 程序中的声明语句叫作定义声明语句,简称定义。定义会使得编译器为变量分配内存。 ⚠️注意:声明不一定是定义。...注意点:类描述了一种数据类型的全部属性(包括使用它执行的操作),对象则是根据描述创建的实体。 C++中信息发送的方式 使用类方法(函数调用等) 重新定义运算符 4....```cpp type functionname(arguementlist) { statements } ```C++ 不允许将函数定义嵌套在另一个函数中,每个函数定义独立。

    72800

    C++雾中风景6:拷贝构造函数与赋值函数

    拷贝构造函数,顾名思义,是一个构造函数,但是它特殊的点就在于在创建对象,是使用同一类中之前创建的对象来初始化新创建的对象。...C++支持两种初始化形式:拷贝初始化(int a = 5;)和直接初始化(int a(5);)对于其他类型没有什么区别,对于类类型直接初始化直接调用实参匹配的构造函数,拷贝初始化总是调用拷贝构造函数,也就是说...一个对象以值传递的方式作为返回值从函数返回 如果我们没有显式声明定义对应类的拷贝构造函数,C++编译器会默认生成对应的拷贝构造函数。...所以我们重载赋值函数的原因也与拷贝构造函数类型,需要实现深度赋值。 由上文的代码也可以看出,赋值函数与拷贝构造函数定义的内容之中,所做的工作大同小异。...而当对象已经存在,用别的对象来给它进行赋值操作,调用的就是赋值函数了。 最后的小Tips:一旦在类之中声明了拷贝构造函数与赋值函数,编译器将不会生成缺省的对应函数。

    61820

    C++ 复制控制之复制构造函数

    不是没有声明复制控制函数编译器就一定会帮类声明,需要满足一定的条件。 C++类用三个特殊的成员函数:复制构造函数、赋值操作符和析构函数 来决定类对象之间的初始化或赋值发生什么。...当定义一个新对象并用一个同类型对象对它进行初始化的时候,将显式使用复制构造函数,如: BOOK book1; BOOK book2(book1);     当将该类型对象传递给函数或从函数返回该类型对象...(C++隐式类型转换),然后调用复制构造函数进行数组元素的复制。...(这部分内容可以参考《Effective C++》条款05)编译器创建的复制构造函数单纯地将来源对象的每一个非static成员拷贝到目标对象,这在很多时候是不能满足类需求的,特别是类中含有指针,这时候就需要我们自己来写复制控制的三个特殊成员函数了...我们可以将复制构造函数定义为private,不允许用户代码复制该类类型对象,若进行复制将在编译发生错误。

    78530

    《Effective Modren C++》 进阶学习(上)

    为了对齐类型,编译器会创建一个临时对象,这个临时对象类型是p想绑定到的对象类型,即m中元素的类型,然后把p的引用绑定到这个临时对象上。在每个循环迭代结束,临时对象将会销毁。...「{}不允许变窄转换,()和=无此禁忌」 在使用{}初始化时,不允许内置类型隐式的变窄转换(narrowing conversion),()和=不检查变窄转换。...(most vexing parse)」 C++规定任何能被决议为一个声明的表达式必须被决议为声明,因此在使用()初始化变量,一些情况会被编译器识别为函数声明。...Widget w1(10); // 没问题,使用实参10调用Widget的一个构造函数 需要初始化一个无参数的构造函数对象,会变成函数声明。...使用constexpr可以在编译对常量表达式进行类型检查和错误检查。如果在常量表达式中使用了不允许的操作或无效的值,编译器会在编译发出错误或警告,帮助我们及早发现并修复问题。 16.

    19620

    嵌入式软件工程师笔试面试指南-CC++

    C++类内可以定义引用数据成员吗? 可以,必须通过成员函数初始化列表初始化。 面向对象与泛型编程是什么? 面向对象编程简称OOP,是一种程序设计思想。...构造函数不能声明为虚函数的原因是: 虚函数的主要意义在于被派生类继承从而产生多态。...虚函数的意思就是开启动态绑定,程序会根据对象的动态类型来选择要调用的方法。然而在构造函数运行的时候,这个对象的动态类型不完整,没有办法确定它到底是什么类型,故构造函数不能动态绑定。...默认参数在函数声明中提供,当有声明又有定义,定义中不允许默认参数。如果函数只有定义,则默认参数才可出现在函数定义中。...所以,在程序中,不管对象类型如何转换,该对象内部的虚函数表指针都是固定的,这样才能实现动态地对对象函数进行调用,这就是C++多态性的原理。 纯虚函数指的是什么

    1.6K11

    C++ 温习笔记(2) - extern,预处理命令#pragma,static

    原因在于,指向类型T的指针并不等价于类型T的数组。extern char *a声明的是一个指针变量而不是字符数组,因此与实际的定义不同,从而造成运行时非法访问。...4)、extern用在变量声明中常常有这样一个作用,你在.c文件中声明了一个全局的变量,这个全局的变量如果要被引用,就放在.h中并用extern来声明。...extern “C” extern “C”的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern “C”后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。...由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数不会带上函数的参数类型,一般只包括函数名。...static 静态数据成员不能在类中初始化,实际上类定义只是在描述对象的蓝图,在其中指定初值是不允许的。

    70310

    C++基础-类和对象

    面向对象编程有四个重要的基础概念:抽象、封装、继承和多态。本文整理 C++ 中类与对象的基础内容,涉及抽象和封装两个概念。《C++基础-继承》一文讲述继承概念。《C++基础-多态》一文讲述多态概念。...语句 Human xiaoMing; 和 int a; 本质上并无不同,对象和类的关系,等同于变量和类型的关系。...原因就是每当对象被复制,编译器都将调用复制构造函数,如果参数不是引用,实参不断复制给形参,将生成不断复制不断调用复制构造函数。...关于复制构造函数的注意事项如下: 类包含原始指针成员(char *等),务必编写复制构造函数和复制赋值运算符。 编写复制构造函数,务必将接受源对象的参数声明为 const 引用。...构造函数与析构函数的其他用途 4.1 不允许复制的类 假设要模拟国家政体,一个国家只能一位总统,President 类的对象不允许复制。 要禁止类对象被复制,可将复制构造函数声明为私有的。

    98020

    轻松搞定面试中的“虚”

    在基类用virtual声明成员函数为虚函数。这样就可以在派生类中重新定义此函数,为它赋予新的功能,并能方便地被调用。在类外定义虚函数,不必再加virtual。该函数就是虚函数了。...5.是否可以将构造函数声明为virtual? 虚函数的意思就是开启动态绑定,程序会根据对象的动态类型来选择要调用的方法。...然而在构造函数运行的时候,这个对象的动态类型不完整,没有办法确定它到底是什么类型,故构造函数不能动态绑定。...C++中是不可以在构造父类对象部分的时候调用子类的虚函数实现。...c++通过下面两个操作符提供RTTI: (1)typeid:返回指针或引用所指对象的实际类型。 (2)dynamic_cast:将基类类型的指针或引用安全的转换为派生类型的指针或引用。

    67620

    从示例入手了解惯用法之PIMPL

    正是基于这个原因,才引入了PIMPL这一惯用法。 从一个例子入手 为了从直观上了解PIMPL带来的好处,我们且看一个例子。...横空出世 正如前面代码中类Car所示,其所依赖的CarImp成员变量为其私有,对于对象类型的变量,必须包含其相应的头文件car_imp.h,否则将会编译失败,如果将其声明为指针方式呢?...+中,有一条这样的规则:如果指针的类型为void*或者指向的类型不完整(前向声明),则删除指针可能会导致未定义的行为。...如果仅向前声明类型,则std::unique_ptr拒绝编译以及调用删除,从而防止潜在的未定义行为。...标准规定,如果定义的类中,为声明析构函数,则编译器会帮忙生成它,但是,编译器生成的方法被声明inline,因此直接在头文件中实现,又因为头文件中仅仅是前向声明类型不完整,这就导致类编译失败。

    14710
    领券