编译器对c++的头文件有看法哦,反正编译器是大佬

项目属性----〉配置属性---->c/c+±—>常规—>附加包含目录----->$(ProjectDir)

缺少vs2017缺少头文件的解决方法
1.调出项目属性页,选择vc++目录
2.包含目录添加头文件路径
3.库目录中添加路径

每次添加都太麻烦了,新建项目都要重新添加,进行通用设置。
选中属性管理器,再点击“Debug|Win32>>MicroSoft.Cpp.Win32.User
双击调处属性页添加路径

c++语言支持分别编译,一个程序中的所有内容,可以分成不同的部分分别放在不同的cpp文件,只需要分别编译成不同的目标文件然后再与其它文件做好连接就行了

如果只有一个函数,那声明起来还不是很困难,但面对多个函数时,就得使用头文件了,所谓的头文件,其实内容和cpp文件内容都是一样的,都是c++源代码,但是头文件不用被编译,把所有声明函数放进头文件,
通过一个宏命令“#include”包含进这个.cpp文件中,当.cpp被编译时,头文件就起作用了。
举个例子
/math.cpp/
double f1()
{
//do something here…
return;
}
double f2(double a)
{
//do something herre,
return a*a;
}
/end of math.cpp/
并把这些函数的声明放在头文件math.h中,
/math.h/
double f1()
double f2(double);
/end of math.h/
在另外一个.main.cpp文件要调用这两个函数,只需要把头文件包含近来
/main.cpp/
#include"math.h"
main()
{int number1 = f1();
int number2 = f2(number1);
}
.h头文件必须和main.cpp同个目录下

重点

头文件中可以写const对象的定义。因为全局的const对象默认是没有exterm的声明的,所以它只在当前文件有效。当这些对象被包含到其他cpp文件时并不是可见的,所以不存在重复定义。同理,static对象的定义也可以放进头文件。

那什么是const对象以及exterm,还有static呢

常类型是指使用类型符修饰符号const说明的类型,常量类型的值或者对象的值是不能被更新的,当然这只该类型的指针或者引用自己认为的,我们可以通过其它的地址空间进行更新。

const推出的初始目的,是为了取代预编译指令

作用:(1)定义const常量
(2)便于进行类型检查
(3)为函数重载提供一个参考
class A{
void f(int i){}//一个函数
void f(int i)const{}//上一个函数的重载
};
(4)可以节省空间,避免不必要的内存分配
例如:
#define PI 3.14159//常量宏
const double PI = 3.14159;//此时并未将pi放入到ROM中。。
double i = Pi;//此时为Pi分配内存,以后不再分配
const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是像#define一样给出的是立即数,所以const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干份拷贝
(7)提高了效率,编译器不会为普通的const常量分配存储空间,而是将他们保存在符号表中,没有存储和读内存的操作
使用方法:
修饰常量 const int x = 2或int const x = 2;
修饰指针
const int *A;//const修饰的对象A可变,A指向的对象不可变
int const *A;//const修饰指向的对象A可变,A指向的对象不可变
int *const A;//const修饰的指针A,A不可变,A指向的对象可变
const int *const A;//指针A和A所指的对象都不可以变
修饰常引用,该引用所引用的对象不能被更新,其定义格式如下:
const double & v;
修饰函数的常参数,修饰函数的传递参数,
void Fun(const int Var);告诉编译器Var在函数体中无法改变,防止使用者无意或错误的修改。
修饰函数的返回值
修饰类的成员函数:
class ClassName{
public:
int Fun() const;
};
这样调用函数Fun时候就不能改变类里面的数据了
最常用的用法

在另一个连接文件中引用const常量
extern const int i;//正确的引用
extern const int j = 10;//错误,常量不可以被再次赋值,另外还要注意,常量必须被初始化,例如:const int i = 5;

ok

那说了这么多,const到底意味着什么呢
是一种修饰符,还是接口抽象,还是一种新类型,也许都是。
在stroustup(C++之父)最初引入这个关键字时,只是为对象放入ROM
做出一种可能,对于const对象,c++允许对其进行静态初始化(预编译时对常量进行初始化)和动态初始化(在程序运行时,根据需要,动态分配空间并赋值)(在汇编中声明并初始化一个变量时,sub esp,4;
mov [esp],0
让栈指针向上移动四个字节)
所以const对象具有从构造函数完成到析构函数执行之前的不变性

对了,讲到这里。或许会有人对构造函数和析构不知为何物

通俗的说,在类中,函数名和类名相同的函数称为构造函数,它的作用是在建立一个对象时,作某些初始化的工作(例如对数据赋予初值)。
c++允许同名函数,也就允许在一个类中有多个构造函数。如果一个都没有,编译器将为该类产生一个默认的构造函数。
构造函数唯一的语法缺点就是不能指定返回类型,甚至void也不行。
不带参数的构造函数 类名 对像名(){函数体}
带参数的构造函数,通过传递给构造函数的参数,可以赋予对象不同的初始值,构造函数名字(形参表)
创建对象使用时 类名 对象名(实参表)
当一个类的对象离开使用域时,析构函数将被调用,析构函数的名字和类名相同,不过要在前面加~,一个类只允许一个析构函数,清理工作释放在堆中分配的内存。

位元const OR 抽象const

例子一:
class A
{
pubilc:
A f(const A& a);

};
抽象const解释:f函数不会去改变所引用对象的抽象值
位元const解释:f函数不会去改变所引用对象的任何位元
位元解释正是c++对const问题的定义,const成员函数不允许修改它所在对象的任何一个数据成员
最大的好处就是编译器容易检测到违反位元const规定的事件:编译器只用去寻找有没有对数据成员的赋值就行了,还有优化作用
至于抽象const比位元const的有优点,就是抽象const级别高,使用库容易。

放在类内部的常量有什么限制呢?
class A{
private:
const int c3 = 7;
static int c4 = 7;
static const float c5 = 7;
};
上诉例子是错误的,使用这种类内部的初始化语法时,常量必须是被一个常量表达式初始化的整形或枚举类型,而且必须是static和const形式。这样做的目的是因为类在一个头文件被声明时,投文件被包含到许多互相调用的单元去,但是为了避免复杂的编译器规则,c++要求每一个对象只有一个单独的定义。如果c++允许在类内部定义一个和对象一样占据内存内存的实体的话,这种规则就被破坏了。
那如何初始化类内部的常量:
1初始化列表法
class A{
public:
A(int i=0):test(i){}
private:
const int i;
}
class A{
public:
A(){}
private:
static const int i;//注意必须是静态的!
};
const int A::i=3;
****常量与数组的组合有什么特殊呢
const int size[3]={10,20,50};
int array[size[2]];
编译通不过,为什么呢
const可以用于集合,但编译器不能把一个集合存放在它的符号表里,所以必须分配内存。这时const意味着不能改变的一块存储。其值在编译时不能被使用,因为编译器在编译时不需要知道存储的内容,自然作为数组的大小就不行了

好吧回到我们之前的内容

#include是一个来自c语言的宏命令,在预编译时候,把后面那个文件内容完整的包涵到担当前文件。于是头文件只能写形如 extern int a;void f();的语句这样才是声明,int a; void f() {}这种就不行。
但是,这个规则是有三个例外的。

一、头文件中可以写const对象的定义。因为全局的const对象默 认是没有extern的声明的,所以它只在当前文件中有效。把这样的对象写进头文件中,即使它被包含到其他多个.cpp文件中,这个对象也都只在包含它的 那个文件中有效,对其他文件来说是不可见的,所以便不会导致多重定义。同时,因为这些.cpp文件中的该对象都是从一个头文件中包含进去的,这样也就保证 了这些.cpp文件中的这个const对象的值是相同的,可谓一举两得。同理,static对象的定义也可以放进头文件。

二、头文件中可 以写内联函数(inline)的定义。因为inline函数是需要编译器在遇到它的地方根据它的定义把它内联展开的,而并非是普通函数那样可以先声明再链 接的(内联函数不会链接),所以编译器就需要在编译时看到内联函数的完整定义才行。如果内联函数像普通函数一样只能定义一次的话,这事儿就难办了。因为在 一个文件中还好,我可以把内联函数的定义写在最开始,这样可以保证后面使用的时候都可以见到定义;但是,如果我在其他的文件中还使用到了这个函数那怎么办 呢?这几乎没什么太好的解决办法,因此C++规定,内联函数可以在程序中定义多次,只要内联函数在一个.cpp文件中只出现一次,并且在所有的.cpp文 件中,这个内联函数的定义是一样的,就能通过编译。那么显然,把内联函数的定义放进一个头文件中是非常明智的做法。

三、头文件中可以写类 (class)的定义。因为在程序中创建一个类的对象时,编译器只有在这个类的定义完全可见的情况下,才能知道这个类的对象应该如何布局,所以,关于类的 定义的要求,跟内联函数是基本一样的。所以把类的定义放进头文件,在使用到这个类的.cpp文件中去包含这个头文件,是一个很好的做法。在这里,值得一提 的是,类的定义中包含着数据成员和函数成员。数据成员是要等到具体的对象被创建时才会被定义(分配空间),但函数成员却是需要在一开始就被定义的,这也就 是我们通常所说的类的实现。一般,我们的做法是,把类的定义放在头文件中,而把函数成员的实现代码放在一个.cpp文件中。这是可以的,也是很好的办法。 不过,还有另一种办法。那就是直接把函数成员的实现代码也写进类定义里面。在C++的类中,如果函数成员在类的定义体中被定义,那么编译器会视这个函数为 内联的。因此,把函数成员的定义写进类定义体,一起放进头文件中,是合法的。注意一下,如果把函数成员的定义写在类定义的头文件中,而没有写进类定义中, 这是不合法的,因为这个函数成员此时就不是内联的了。一旦头文件被两个或两个以上的.cpp文件包含,这个函数成员就被重定义了。

五、头文件中的保护措施
考 虑一下,如果头文件中只包含声明语句的话,它被同一个.cpp文件包含再多次都没问题——因为声明语句的出现是不受限制的。然而,上面讨论到的头文件中的 三个例外也是头文件很常用的一个用处。那么,一旦一个头文件中出现了上面三个例外中的任何一个,它再被一个.cpp包含多次的话,问题就大了。因为这三个 例外中的语法元素虽然“可以定义在多个源文件中”,但是“在一个源文件中只能出现一次”。设想一下,如果a.h中含有类A的定义,b.h中含有类B的定 义,由于类B的定义依赖了类A,所以b.h中也#include了a.h。现在有一个源文件,它同时用到了类A和类B,于是程序员在这个源文件中既把 a.h包含进来了,也把b.h包含进来了。这时,问题就来了:类A的定义在这个源文件中出现了两次!于是整个程序就不能通过编译了。你也许会认为这是程序 员的失误——他应该知道b.h包含了a.h——但事实上他不应该知道。
使用"#define"配合条件编译可以很好地解决这个问题。在一 个头文件中,通过#define定义一个名字,并且通过条件编译#ifndef…#endif使得编译器可以根据这个名字是否被定义,再决定要不要继 续编译该头文中后续的内容。这个方法虽然简单,但是写头文件时一定记得写进去。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值