美文网首页c++
c++学习笔记——第一天

c++学习笔记——第一天

作者: 我就是一个垃圾 | 来源:发表于2019-02-07 21:07 被阅读4次

一、c++综述

(1)书籍推荐

①、c++ primer

②、c++ primer plus

③、c++编程思想

(2)c++历史

1982 年,美国 AT&T 公司贝尔实验室的 Bjarne Stroustrup 博士在 c 语言的基础上引入并扩充了面向对象的概念,发明了一种新的程序语言。为了表达该语言与 c 语言的渊源关系,它被命名为 C++。而 Bjarne Stroustrup(本贾尼·斯特劳斯特卢普)博士被尊称为C++语言之父。

各种语言排行榜可以到这个网站去找http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html

一本电子书

链接:https://pan.baidu.com/s/1PiV3Flzp5g4Gwdfcb60oBg

提取码:z9eq

复制这段内容后打开百度网盘手机App,操作更方便哦

二、c++相对于c的类型增强

(1)类型检查更严格

例如:在c语言中const int a=10;可以用指针对a进行更改,而在c++中不可以这样更改,类型更强了。所以说c++中的const是真正的const。不可以更改了。

(2)增加了bool类型、字符串类型(其实不是类型,是一个类,可以理解成类型)

string s;

bool b =true;//true代表1,可以直接用true和false

也可以赋值给b整数 如100等 c++中的bool其实就是一种bool类型

在C语言中使用enum和struct类型时,如在C语言中struct student{int a;int b;};在用的时候只能用struct student liming而在c++中就可以直接引用student liming来定义变量

当然 也可以用typedef进行类型转换,sizeof(bool)=1

(3)真正的枚举

c 语言中枚举本质就是整型,枚举变量可以用任意整型赋值。而 c++中枚举变量,只能

用被枚举出来的元素初始化。

(4)部分表达式可以赋值

 C语言中,表达式是不可以被赋值的, (a = b) = 100,这种是错的; 而C++中,表达式可以被赋值, (a = b) = 100,这是对的。先把b的值赋给a,再把100赋值给a;

三、c++的输入输出

cin cout 这是类对象

printf,scanf这是函数

一个非常简单的c++程序:

include <iostream>

using namespace std;

int main()

{

    cout << "hello world "<< endl;

    return 0;

}

fgets(name,30,stdin);//只能读29个

C语言中scanf("%d%c",&a&b);这样是不可以的,会把空格吃掉,最好是scanf("%d",&a);getchar();

用cin也是中间不能出现空格,不然空格后面的就会吃掉

设置输入输出格式

对于实型,cout 默认输出六位有效数据,setprecision(2) 可以设置有效位数,setprecision(n)<<setiosflags(ios::fixed)合用,可以设置小数点右边的位数。

include <iostream>

using namespace std;

int main()

{

int a=12345;

float b=4.8928972929;

cout<<setiosflags(ios::left)<<setw(8)<<a<<endl;//左对齐,域宽

cout<<setw(10)<<setprecision(2)<<setiosflags(ios::fixed)<<b<<endl;//小数点后两位

    return 0;

}

输出十进制,十六进制,八进制。默认输出十进制的数据。

int i = 123;

cout<<i<<endl;

cout<<dec<<i<<endl;

cout<<hex<<i<<endl;

cout<<oct<<i<<endl;

cout<<setbase(16)<<i<<endl;

设置填充符

还可以设置域宽的同时,设置左右对齐及填充字符。

应该包含一个头文件,是一个<iomanip>

int main()

{

cout<<setw(10)<<1234<<endl;

cout<<setw(10)<<setfill('0')<<1234<<endl;

cout<<setw(10)<<setfill('0')<<setiosflags(ios::left)<<1234<<endl;

cout<<setw(10)<<setfill('-')<<setiosflags(ios::right)<<1234<<endl;

return 0;

}

四、函数重载(静多态)

重载就是一个东西两种用法,由语境决定(C语言没有,c++中才有)    ambiguous(二义性)

①函数的名字相同,参数列表,个数,顺序,类型不同,但是返回值类型不构成重载条件

②匹配原则:严格匹配,不能严格匹配时进行隐式类型转换

重载原理:

重载底层实现(name mangling)

C++利用 name mangling(倾轧)技术,来改名函数名,区分参数不同的同名函数。

实现原理:用 v-c- i-f- l- d 表示 void char int float long double 及其引用。

void func(char a);                                 // func_c(char a)

void func(char a, int b, double c);        //func_cid(char a, int b, double c)

c++中倾轧就都倾轧,不倾轧就都不要倾轧

extern “C”(取消倾轧)

name mangling 发生在两个阶段,.cpp 编译阶段,和.h 的声明阶段。

只有两个阶段同时进行,才能匹配调用。

mystring.h

extern "C" {

int myStrlen(char *str);

}

mystring.cpp

int myStrlen(char *str)

//#include "mystring.h"

int myStrlen(char *str)

{

int len = 0;

while(*str++)

len++;

return len;

}

main.cpp

#include

#include "mystring.h"

using namespace std;

int main()

{

char *p = "china";

int len;

len = myStrlen(p);

return 0;

}

c++ 完全兼容 c 语言,那就面临着,完全兼容 c 的类库。由.c 文件的类库文件中函数名,

并没有发生 name mangling 行为,而我们在包含.c 文件所对应的.h 文件时,.h 文件要发生

name manling 行为,因而会发生在链接的时候的错误。

C++为了避免上述错误的发生,重载了关键字 extern。只需要,要避免 name manling

的函数前,加

extern "C" 如有多个,则 extern "C"{}

我们看一个系统是怎么处理的:

sting.h

extern "C" {

char * __cdecl _strset(char *_Str,int _Val) __MINGW_ATTRIB_DEPRECATED_S

EC_WARN;

char * __cdecl _strset_l(char *_Str,int _Val,_locale_t _Locale) __MINGW

_ATTRIB_DEPRECATED_SEC_WARN;

char * __cdecl strcpy(char * __restrict__ _Dest,const char * __restrict

__ _Source);

char * __cdecl strcat(char * __restrict__ _Dest,const char * __restrict

__ _Source);

int __cdecl strcmp(const char *_Str1,const char *_Str2);

size_t __cdecl strlen(const char *_Str);

size_t __cdecl strnlen(const char *_Str,size_t _MaxCount);

void *__cdecl memmove(void *_Dst,const void *_Src,size_t _Size) __MINGW

_ATTRIB_DEPRECATED_SEC_WARN;

}

五、操作符重载

c++认为一切操作符都是函数(有的操作符不这样认为……),函数是可以重载的,但是并不是所有的运算符都可以重载的

前面用到的<<本身在 c 语言中是位操作中的左移运算符。现在又用用流插入运算符,这

种一个字符多种用处的现像叫作重载。在 c 语中本身就用重载的现像,比如 & 既表示取地址,

又表示位操作中的与。*既表示解引用,又表示乘法运算符。

只不过 c 语言并没有开放重载机制。

C++提供了运算符重载机制。可以为自定义数据类型重载运算符。实现构造数据类型也

可以像基本数据类型一样的运算特性。

using namespace std;

struct COMP

{

float real;

float image;

};

COMP operator+(COMP one, COMP another)

{

one.real += another.real;

one.image += another.image;

return one;

}

int main()

{

COMP c1 = {1,2};

COMP c2 = {3,4};

COMP sum = operator+(c1,c2); //c1+c2;

cout<

return 0;

}

示例中重载了一个全局的操作符+号用于实现将两个自定义结构体类型相加。本质是函数

的调用。

当然这个 COMP operator+(COMP one, COMP another),也可以定义为 COMP

add(COMP one, COMP another),但这样的话,就只能 COMP sum = add(c1,c2),而不

能实现 COMP sum = c1 +c2 了。

后序我们在学习完成类以后,重点讲解重载。

六、c++函数默认参数(默认参数(default parameters) )

通常情况下,函数在调用时,形参从实参那里取得值。对于多次调用用一函数同一实参

时,C++给出了更简单的处理办法。给形参以默认值,这样就不用从实参那里取值了。

当声明和定义不在一起时,默认参数应该写在声明处而不是定义处

单个参数

#include

#include

using namespace std;

void weatherForcast(char * w="sunny")

{

time_t t = time(0);

char tmp[64];

strftime( tmp, sizeof(tmp), "%Y/%m/%d %X %A ",localtime(&t) );

cout<

}

int main()

{

//sunny windy cloudy foggy rainy

weatherForcast();

weatherForcast("rainny");

weatherForcast();

return 0;

}

多个参数

float volume(float length, float weight = 4,float high = 5)

{

return length*weight*high;

}

int main()

{

float v = volume(10);

float v1 = volume(10,20);

float v2 = volume(10,20,30);

cout<<v<<endl;cout<<v1<<endl;cout<<v2<<endl;

return 0;

}

规则

1,默认的顺序,是从右向左,不能跳跃。

2,函数声明和定义一体时,默认参数在定义(声明)处。声明在前,定义在后,

默认参数在声明处。

3,一个函数,不能既作重载,又作默认参数的函数。当你少写一个参数时,系统无法

确认是重载还是默认参数。

void print(int a)

{ }

void print(int a,int b =10)

{ }

int main()

{

print(10);

return 0;

}

main.cpp:16: error: call of overloaded 'print(int)' is ambiguous

print(10);

七、引用(&)

引用的同时也要初始化

变量名,本身是一段内存的引用,即别名(alias)。此处引入的引用,是为己有变量起一个

别名。

声明如下:

int main()

{

int a;

int &b = a;

}

规则

1,引用没有定义,是一种关系型声明。声明它和原有某一变量(实体)的关系。故而类型

与原类型保持一致,

且不分配内存。与被引用的变量有相同的地址。

2,声明的时候必须初始化,一经声明,不可变更。

3,可对引用,再次引用。多次引用的结果,是某一变量具有多个别名。

4,&符号前有数据类型时,是引用。其它皆为取地址。

引用的本质是指针,C++对裸露的内存地址(指针)作了一次包装。又取得的指针的优良特性。所以再对引用取地址,建立引用的指针没有意义。

1,可以定义指针(int*也算是一种类型)的引用,但不能定义引用的引用。

int a;

int* p = &a;

int*& rp = p; // ok

int& r = a;

int&& rr = r; // error

案例:

#include <iostream>

using namespace std;

void swap(char *pa,char *pb)

{

char *t;

t = pa;

pa = pb;

pb = t;

}

void swap2(char **pa,char **pb)

{

char *t;

t = *pa;

*pa = *pb;

*pb = t;

}

void swap3(char * &pa,char *&pb)

{

char *t;

t = pa;

pa = pb;

pb = t;

}

int main()

{

char *pa = "china";

char *pb = "america";

cout<<"pa "<<pa<<endl;

cout<<"pb "<<pb<<endl;

// swap(pa,pb);

// swap2(&pa,&pb);

swap3(pa,pb);

cout<<"pa "<<pa<<endl;

cout<<"pb "<<pb<<endl;

return 0;

}

2,可以定义指针的指针(二级指针),但不能定义引用的指针。

int a;

int* p = &a;

int** pp = &p; // ok

int& r = a;

int&* pr = &r; // error

3,可以定义指针数组(数组 int 【3】也可以当成一种类型),但不能定义引用数组,可以定义数组引用。

int a, b, c;

int* parr[] = {&a, &b, &c}; // ok

int& rarr[] = {a, b, c}; // error

int arr[] = {1, 2, 3};

int (&rarr)[3] = arr; // ok

4,常引用

const 引用有较多使用。它可以防止对象的值被随意修改。因而具有一些特性。

(1)

const 对象的引用必须是 const 的,将普通引用绑定到 const 对象是不合法的。 这

个原因比较简单。既然对象是 const 的,表示不能被修改,引用当然也不能修改,必须使

用 const 引用。实际上,const int a=1; int &b=a;这种写法是不合法的,编译不过。

(2)

const 引用可使用相关类型的对象(常量,非同类型的变量或表达式)初始化。这个是

const 引用与普通引用最大的区别。const int &a=2;是合法的。double x=3.14; const int

&b=a;也是合法的。

常引用原理:

const 引用的目的是,禁止通过修改引用值来改变被引用的对象。const 引用的初始化

特性较为微妙,可通过如下代码说明:

double val = 3.14;

const int &ref = val; // int const & int & const ??

double & ref2 = val;

cout<<ref<<" "<<ref2<<endl;

val = 4.14;

cout<<ref<<" "<<ref2<<endl;

上述输出结果为 3 3.14 和 3 4.14。因为 ref 是 const 的,在初始化的过程中已经给

定值,不允许修改。而被引用的对象是 val,是非 const 的,所以 val 的修改并未影响 ref

的值,而 ref2 的值发生了相应的改变。

那么,为什么非 const 的引用不能使用相关类型初始化呢?实际上,const 引用使用相

关类型对象初始化时发生了如下过程:

int temp = val;

const int &ref = temp;

如果 ref 不是 const 的,那么改变 ref 值,修改的是 temp,而不是 val。期望对 ref 的

赋值会修改 val 的程序员会发现 val 实际并未修改。

int i=5;

const int & ref = i+5;

//此时产生了与表达式等值的无名的临时变量,

//此时的引用是对无名的临时变量的引用。故不能更改。

cout<<ref<<endl;

5,尽可能使用 const

use const whatever possible 原因如下:

1,使用 const 可以避免无意修改数据的编程错误。

2,使用 const 可以处理 const 和非 const 实参。否则将只能接受非 const 数据。

3,使用 const 引用,可使函数能够正确的生成并使用临时变量(如果实参与引用参

数不匹配,就会生成临时变量)

引用的本质浅析

1.大小与不可再引用

引用的本质是指针,是个什么样指针呢?可以通过两方面来探究,初始化方式和大小。

struct TypeP

{

char *p;

};

struct TypeC

{

char c;

};

struct TypeR

{

char& r; //把引用单列出来,不与具体的对像发生关系

};

int main()

{

// int a;

// int &ra = &a;

// const int rb; //const类型必须要初始化。

printf("%d %d %d\n",sizeof(TypeP),sizeof(TypeC),sizeof(TypeR));

return 0;

}

结论:

引用的本质是,是对常指针 type * const p 的再次包装。

char &rc == *pc double &rd == *pd

可以参考的文章:https://blog.csdn.net/luoweifu/article/details/39119487

https://blog.csdn.net/tianxiaolu1175/article/details/46889523

引用的数组和数组的引用 https://blog.csdn.net/kbccs/article/details/80114971

相关文章

网友评论

    本文标题:c++学习笔记——第一天

    本文链接:https://www.haomeiwen.com/subject/xvabsqtx.html