C++ Primer 知识点(个人笔记)持续更新···

变量声明和定义的关系

C++支持分离式编译机制,该机制允许将程序分成若干个文件独立进行编译。
如果想声明一个变量而非定义它,就需要使用关键字 extern ,而且不要显式地初始化变量。

extern int i;  //声明i而非定义i
int j;  //定义j
extern double pi=3.14;  //定义

声明和定义看起来微不足道,但是当我们要在多个文件中用到一个变量时,我们就会很经常地用到这个用法。
此时,变量的定义必须出现且只能出现在一个文件中,而其他文件中想要用到该变量,必须头文件#include" ",然后再对其进行声明,而不能再次对其进行定义。

命名空间的 using 声明

using namespace :: name;

//一旦声明上述语句,就可以直接访问命名空间中的名字
//具体体现为:
using std::cin;
using std::cout; using std::endl;

值得注意的时:头文件中一般不应该包含using声明。因为每个使用该头文件的文件都会包含该头文件,也就是会包含using声明,可能会出现不可预料的冲突。

string中 cin 输入和 getline 输入

string s1;
//假如我们想将Hello world输入给s1
while(cin>>s1)//此时读到空白格就不读了
{
	cout<<s1<<endl;
}
//输出结果为:Hello
//			  world
//不在同一行
string s2;
while(getline(cin,s2))//此时读到空白格也会继续读,直至读到回车
{
	cout<<getline<<endl;
}
//输出结果为:hello world

size()函数的返回值类型

size()函数的返回值类型不是int,但是也可以当成int使用,它的返回值类型实际上是unsigned long long;

auto 和 decltype 的区别

auto和decltype都是用来自动适配类型的关键字,区别在于当我们想用一个表达式或者函数的返回值的类型来作为一个变量或者函数的返回值类型时,可以用decltype来避免直接复制,具体体现为:

decltype(s.size()) n=x.size();
auto n=x.size();

标准库函数begin()和end()

对于指针要使用begin()和end()这两个函数,需要引入头文件#include
使用示例:

#include
int ia[]={0,1,2,3,4,5,6,7,8,9};
int *beg=begin(ia);  //beg是指向数组首元素的指针
int *last=end(ia);  //last是指向数组尾元素后一位的指针

数组不允许直接拷贝

int a[]={0,1,2,3,4};  //初始化数组a
int b[]=a;  //错误,不能直接用b来初始化a

数组形参

数组形参 = 指向数组首元素的指针形参

//下面这三种函数的声明是等价的,都是接受数组作为形参,只是表达方式不同
void print(const int[]);
void print(const int *);
void print(const int[10]);  //数组长度为10并不是确定的,只是我们期望它为10
//这些函数的形参都是 const int * 类型
//调用
int i=18;
print(&i);  //合法
int j={0,1,2};
print(j);  //合法,j转换成 const int * 类型并指向j[0]

含有可变形参的函数

当无法预知函数形参需要几个时,比如当我们需要打印整个程序的错误信息时,此时所有形参尽管不知道要提供多少个,但是我们知道他的形参类型时相同的,我们就可以用initializer_list类型的形参,initializer_list是一种标准库类型。

//类似于vector,initializer_list也是一种模板类型
initializer_list<string> lst;  //定义元素类型是string
//和vector不一样的是:initializer_list中的元素  永远是常量值  
//输出错误信息的函数
void error_msg(initializer_list<string> lst)
{
	for(auto beg=lst.begin();beg!=lst.end();lst++)
	{
		cout<<*beg<<" ";
	}
	cout<<endl;
}

//如果想向形参传递一个值的序列,则必须把序列放在一对花括号里

//expected和actual是string对象
if(expected!=actual)
{
	error_msg({"function",expected,actual});  //这里传递了三个形参
}
else
{
	error_msg({"function","Okay"});  //这里传递了两个形参
}

main函数

int main()函数的结尾如果没有return语句,编译器将隐式地插入一条 return 0;,main函数的返回0表示执行成功,返回其他值表示执行失败。

名字查找 与 类型检查

在C++中,名字查找 先于 类型检查

内联函数

我们一般习惯将一小块功能封装成函数,当需要时调用即可。
但是调用函数比一般求等价表达式要慢一些,涉及到寄存器的保存,并在返回时恢复;可能需要拷贝实参;程序转向一个新的地方继续运行。

此时就引入内联函数:它可以避免函数调用的开销。
(常量表达式函数constexpr被编译器隐式地指定为内联函数)
但是内联函数存在其局限性:

内联机制通常作用于代码块小且又经常被调用的函数,毕竟不可能每个函数都定义为内联函数,然后出现几百行的展开

//shortstring()是一个返回较短字符串的函数
//当将其封装内联函数时,只需要在返回值类型前加上 inline 关键字
inline const string &shortstring(const string &s1,const string &s2)
{
    return s1.size()<=s2.size() ? s1 : s2;
}

//以上函数在编译后,调用时会展开成类似于下面这种形式
cout<<shortstring(s1,s2)<<endl;  //表面形式
cout<<(s1.size()<=s2.size() ? s1 : s2)<<endl;  //编译后的形式

函数指针

bool lengthcompare(const string &,const string &);
//将函数名替换成指针就可以
bool (*pf) (const string &,const string &);
//此时pf是一个函数指针,指向lengthcompare函数

#include
using namespace std;

const string stringcompare(const string &s1,const string &s2)
{
    return s1.size()<=s2.size() ? s1 : s2;
}

int main()
{
    string s1="ab";
    string s2="dajdj";
    const string (*pf) (const string &,const string &); //pf是函数指针
    pf=stringcompare;
    string s=pf(s1,s2);
    //string s=stringcompare(s1,s2);
    cout<<s<<endl;
}

你可能感兴趣的:(C++基础,c++,visual,studio,C++primer)