C++学习笔记(《C++新经典》基础部分)

2023-05-16

文章目录

  • 第 9 章 指针
    • 9.2 变量的指针和指向变量的指针变量
      • 9.2.3 指针变量作为函数参数
  • 第 10 章 结构体与共用体
    • 10.1 结构体类型定义,结构体变量的定义、引用与初始化
      • 10.1.1 定义一个结构体类型
      • 10.1.2 定义一个结构体类型变量
      • 10.1.3 结构体类型变量的引用
      • 10.1.4 结构体变量的初始化
    • 10.2 结构体数组与结构体指针
      • 10.2.1 结构体数组
      • 10.2.2 结构体指针
    • 10.3 共用体、枚举类型与typedef
      • 10.3.3 用typedef定义类型
  • 第 13 章 C++基本语言
    • 13.1 语言特性、工程构成与可移植性
      • 13.1.1 语言特性:过程式、对象式程序设计
      • 13.1.2 C++程序和项目文件构成
    • 13.2 命名空间简介与基本输入/输出精解
      • 13.2.1 命名空间简介
      • 13.2.2 基本输入/输出

第 9 章 指针

9.2 变量的指针和指向变量的指针变量

9.2.3 指针变量作为函数参数

  1 #include <stdio.h>
  2 void swap(int *pdest1, int *pdest2)
  3 {
  4     int temp;
  5     temp = *pdest1;
  6     *pdest1 = *pdest2;
  7     *pdest2 = temp;
  8 }
  9 int main()
 10 {
 11     int a = 5,b = 6;
 12     int *p1,*p2;
 13     p1 = &a;
 14     p2 = &b;
 15     printf("a = %d,b = %d\n",a,b);
 16     if(a<b)
 17     {
 18         swap(p1,p2);
 19         }
 20     printf("a = %d,b = %d\n",a,b);
 21 }

这个范例并不复杂,这里以指针变量作为实参,传递到swap函数(swap函数用于交换两个变量的值),实参是两个指针变量p1和p2,swap函数函数中对应的两个形参是pdest1和pdest2,而在swap函数中,实际上就是把a的值赋给中间变量temp,把b的值赋给a,然后再把中间变量temp的值赋给b,从而实现a和b两个变量值的交换。

一般来说,#include命令主要用来包含一些.h头文件。在这段程序的第一行,包含了标准头文件studio.h,这主要是因为主程序中用到了printf函数。

1 #include <stdio.h>   // 用<>将文件包含起来
1 #include “stdio.h”   // 用“”将文件包含起来

用尖括号<>括起来的头文件被#include时,表示让编译器去系统目录中寻找stdio.h,所以一些系统提供的标准头文件在#include时都应该使用尖括号<>括起来。而用双引号“”包含起来的头文件被#include时,编译器会首先在当前源代码文件所在目录下寻找,如果找不到,再到系统目录中寻找,所以,通常开发者自己写的一些头文件,在被#include包含进来时,往往使用双引号包含起来。

第 10 章 结构体与共用体

C语言中的结构体是一种数据类型,确切地说是将多种不同类型的数据组合起来构成的一个新数据类型,这个新数据类型能够表达更丰富、更全面的信息。结构体成员数据可以是任意一种C的数据类型,也可以是其他结构体。

结构体是学习C++部分中最重要的的概念“类”的基础,所以必须要学好。

10.1 结构体类型定义,结构体变量的定义、引用与初始化

10.1.1 定义一个结构体类型

struct student				//定义一个结构体类型 student
{
	int num;				//学好
	char name[100];			//姓名
	int sex;				//性别  0:女生,1:男生
	int age;				//年龄
	char address[100];		//地址
}; // 这里的分号,不要忘记

10.1.2 定义一个结构体类型变量

(1)在已经定义了student结构体类型的情况下,

struct student s1,s2;

(2)还可以在定义结构体类型的同时,定义变量,

struct student				//定义一个结构体类型 student
{
	int num;				//学好
	char name[100];			//姓名
	int sex;				//性别  0:女生,1:男生
	int age;				//年龄
	char address[100];		//地址
}s1,s2; //多个变量名之间用逗号隔开

(3)直接定义结构体类型变量, 不定义结构体名,

struct
{
	int num;				//学好
	char name[100];			//姓名
	int sex;				//性别  0:女生,1:男生
	int age;				//年龄
	char address[100];		//地址
}s1,s2; //多个变量名之间用逗号隔开

10.1.3 结构体类型变量的引用

(1)不能直接将结构体变量作为一个整体进行引用,只能对结构体变量中的各个成员分别引用。使用“.”运算符来引用,它的优先级非常高,与圆括号()平级。
(2)结构体中的成员又称为成员变量,可以直接看作普通变量,像普通变量一样进行各种运算,比如赋值、算术运算等。同时,成员变量也是有地址的,可以进行将其地址赋值给指针变量,例如:

int *p = &s1.num;

10.1.4 结构体变量的初始化

案例展示
在Visual Studio 2022中测试下面这一段代码:

#include <iostream>

int main()
{
    float af1 = 0.5;
    float af2;
    af2 = 0.51;
    struct student
    {
        int num;
        char name[100];
        int sex;
        int age;
    } s1,s2;
    s1 = { 1001,"zhangsan",1,18 };
    s2 = { 1002,"lisi",1,23 };
    int * p1 = &s1.age;
    int * p2 = &s2.num;
    char mystr[] = "I love China!";
    printf("%s\n",mystr);
    printf("%d\n", *p1);
    printf("%d\n", *p2);
}

可以正常运行,没有问题。但是将这一段代码复制到linux系统下,用g++编译后就会报错。为了找到报错原因,我使用了一个更短一点的代码来测试,当书写格式如下时,可以正常运行:

  1 #include <iostream>
  2 
  3 int main()
  4 {
  5     struct kids
  6     {
  7         int num;
  8         int age;
  9         char name[20];
 10     };
 11     //struct kids k1 = {100,6,"liuxy"};
 12     struct kids k1 = {100,6,"liuxy"};
 13 
 14     int * p1 = &k1.num;
 15     int * p2 = &k1.age;
 16     char mystr[] = "I love China!";
 17     printf("%s\n", k1.name);
 18     printf("%d\n", *p1);
 19     printf("%d\n", *p2);
 20     printf("%s\n",mystr);
 21 }    

但是,当改变一下结构体变量的定义方式时,就会报错:

  1 #include <iostream>
  2 
  3 int main()
  4 {
  5     struct kids
  6     {
  7         int num;
  8         int age;
  9         char name[20];
 10     } k1;
 11     //struct kids k1 = {100,6,"liuxy"};
 12     k1 = {100,6,"liuxy"};
 13 
 14     int * p1 = &k1.num;
 15     int * p2 = &k1.age;
 16     char mystr[] = "I love China!";
 17     printf("%s\n", k1.name);
 18     printf("%d\n", *p1);
 19     printf("%d\n", *p2);
 20     printf("%s\n",mystr);
 21 }

报错内容如下,暂时没看懂:
在这里插入图片描述
所以为了有更好的移植性,结构体类型的定义和结构体类型变量的定义、初始化最好分开进行?

结构体是以后学习C++中“类”概念的基础,而“类”又是C++中最重要的概念,类跟结构体很类似,甚至可以理解为:类是结构体功能的扩充。

10.2 结构体数组与结构体指针

10.2.1 结构体数组

一个结构体变量可以存放一个学生的学号、年龄等数据,10个甚至更多个学生的数据,就需要使用结构体数组。
结构体数组的定义和初始化:

struct student stuArr[3]={
	{1001,18,"zhang3"},
	{1002,17,"li4"},
	{1003,18,"wang5"},
};

定义的时候初始化还可以不指定数组元素个数,此时系统根据初始化的这些值自动推断出数组的元素个数。

10.2.2 结构体指针

所谓结构体指针,就是结构体变量的指针,用于指向该结构体变量所占据的内存的起始地址。

当然,结构体变量的指针也可以指向结构体数组中的元素,因为结构体数组中的每个元素就相当于一个结构体变量。
指向结构体变量的指针,看如下代码:

struct student stu;		//结构体变量
struct student * ps;	//结构体变量的指针
ps = &stu;

printf("num = %d\n",ps->num);
printf("age = %d\n",ps->age);
printf("name = %s\n",ps->name);

通过结构体变量指针来访问结构体变量成员的方法,使用结构体成员运算符“->”,优先级也是最高的。

指向结构体变量的指针在结构体数组中的应用,看如下代码:

struct student stuArr[3]={
	{1001,18,"zhang3"},
	{1002,17,"li4"},
	{1003,18,"wang5"},
};
struct student * ps;	//结构体变量的指针
ps = stuArr;			//数组名作为数组首地址
for (int i = 0; i < 3; i++)
{
	printf("num = %d\n",ps->num);
	printf("age = %d\n",ps->age);
	printf("name = %s\n",ps->name);
	ps++;			//这个++意味着一次跳过一个数组元素所占的字节数
}
int ilen = sizeof(struct student);
printf("ilen = %d\n", ilen);

关于这段代码的几点说明:
(1)现在ps指向stuArr,也就是数组的第一个元素。看如下代码:

ps = stuArr;	
printf("%d\n",(++ps) -> num);		//1002,++在ps前面,表示先加后用
									//随后指针指向1002

对于如下代码:

ps = stuArr;	
printf("%d\n",(ps++) -> num);		//1001,++在ps后面,表示先用后加
									//随后指针同样指向1002

(2)指针ps定义为指向struct student 类型变量的指针,它只能指向一个结构体类型的变量或者指向一个结构体类型数组中的某个元素,不能指向其中的具体某个成员。例如,下面这些写法是不可以的:

ps = &stu.num;
ps = &stuArr[0].num;

10.3 共用体、枚举类型与typedef

10.3.3 用typedef定义类型

在C语言中,除了提供的标准类型名,如int、char、float、double等,还可以用type关键字来定义新的类型名以替代原有的类型名。注意,typedef是用来定义新类型名的,不是用来定义变量的。看看如下代码

typedef int INTTEGER;

这里通过typedef用INTEGER代表了int。

也可以用typedef定义一个结构体类型:

typedef struct date		//date可以省略
{
	int month;
	int day;
	int year;
}DATE;

上面这段代码定义了一个新的类型名DATE(不是定义了一个结构体变量DATE),代表上面定义的这个结构体类型。现在,就可以用DATE来定义结构体变量了。

这里有一些重要说明,请注意:
(1)习惯上把用typedef定义的类型名用大写字母表示,以便区别于C语言提供的标准类型标志符;
(2)typedef是用来定义各种类型名的,不是用来定义变量的;
(3)typedef只是对已经存在的类型增加一个类型名(相当于给类型起一个别名),并没有创造新类型;
(4)typedef是编译时处理的;
(5)typedef最主要的作用是有利于程序的通用性与可移植性。
例如,写代码时,首先用一个typedef,

typedef int INTEGER;

以后如果想把int 修改成long,不需要把程序中所有的int找出来,只需要把typedef这一行修改了就可以了。例如:

typedef long INTEGER;

所有的int类型变量就都被修改为long类型。

第 13 章 C++基本语言

13.1 语言特性、工程构成与可移植性

13.1.1 语言特性:过程式、对象式程序设计

1. 面向过程式的程序设计
C语言的编程风格是属于过程式的编程设计,或者称为面向过程式的程序设计。所谓过程式的设计语言就是当编写代码解决一个问题时,代码的编写方法是从上到下,逐步求精,一些公用的功能写成函数,需要用到结构体时就定义结构体。

2. 基于对象的程序设计和面向对象的程序设计
C++本身支持C语言风格的过程式程序设计,同时也支持基于对象的程序设计和面向对象的程序设计。
无论是基于对象的程序设计还是面向对象的程序设计,都没有离开一个概念叫“对象”。如何理解“对象”呢?
在C语言部分学习了结构,也叫结构体(一个学生,把学号、名字、性别、成绩等成员变量放在一起,构成结构),但是在C++中,不叫结构,而是叫“”。在C语言中,要使用结构,需要先定义一个属于该结构体的变量(结构体变量),在C++中,不叫结构体变量,叫“对象”。但是类比结构更强大的地方在于:在类中,不仅可以定义成员变量,还可以定义成员函数(也叫方法)以实现一些功能。
范例:

struct dagongzai  //定义一个打工仔结构,也就是打工仔类
{
    //里面有些成员函数(方法)
    void qichuang();                 //起床
    void chuanyifu();                //穿衣服
    void shuaya();                   //刷牙
    void chizaofan();                //吃早饭
    void shangban();                 //上班
    //提供对外接口,供其他人调用,突发事件
    void tufashijian(int eventtype);//突发事件
}
struct dagongzai zhangsan;          //定义一个属于该类的变量(对象)
zhangsan.qichuang();                //通过对象调用成员变量
zhangsan.chuanyifu();

这种把功能包到类中,定义一个类对象并通过该对象调用各种成员函数实现各种功能的程序书写方式,称为基于对象的程序设计

随着发展,需求也在变更,不断出现了许多新需求。假如将来有一种新打工仔职业,如推销员tuixiaoyuan,老板要求推销员在每天正式上班之前,必须要在公司操场前面集合,先集体唱一次国歌,然后再开始手头工作。那么,可以增加一个tuixiaoyuan类,继承自dagongzai类,这一继承,dagongzai类的很多方法,如起床、穿衣服、刷牙、吃早饭、上班等,tuixiaoyuan类就都继承过来了,而且tuixiaoyuan类还可以增加自己的新成员函数changguoge(唱国歌),这在C++中称为继承性

C++中还有一个特性叫多态性,暂时可以这样理解:父类dagongzai和子类tuixiaoyuan都有一个同名的成员函数,那么,在做该成员函数调用时,到底是调用父类的还是调用子类的该函数呢?就会有一些说法了,这种说法就是所谓的多态性。

当把继承性和多态性技术融入程序设计中去时,基于对象的程序设计就升华了,也就是变得更高级了,此时就叫做面向对象的程序设计。所以基于对象和面向对象程序设计的主要区别是:在基于对象的程序设计中额外运用了继承性和多态性技术。通过继承性和多态性,可以少写很多代码,实现很多变化。

13.1.2 C++程序和项目文件构成

(1)一个项目(工程)中可以包含多个.cpp文件和多个.h头文件,一般.cpp叫源文件,.叫头文件。一些公共的定义一般都会放在头文件中(如函数的声明,一些类、结构的定义,一些#define等),然后在源文件中用#include把头文件包含进来使用。

(2)C++的头文件拓展名一般以.h居多。此外,还有.hpp,.hpp一般来讲就是把定义和实现都包含在一个文件里,有一些公共开源库就是这样做,主要是能有效地减少编译次数。

(3)还能够发现,很多C++提供的头文件已经不带扩展名。以往在C语言中经常用到的头文件,如比较熟悉的stdio.h等,在C++98标准之后,都变成了以c开头并去掉拓展名的文件,如stdio.h就变成了cstdio文件。

13.2 命名空间简介与基本输入/输出精解

13.2.1 命名空间简介

命名空间是为了防止名字冲突而引入的一种机制。在一个很大的项目中,包含上百个.cpp文件,而且这上百个.cpp文件一般是一个团队开发的,存在函数名、类名和变量名同名的问题。

系统中可以定义多个命名空间,每个命名空间都有自己的名字,不可以同名。可以把命名空间看成一个作用域,这个命名空间里定义的函数与另外一个命名空间里定义的函数,即便同名,也互不影响。

(1)命名空间的定义:

namespace 命名空间
{
    void radius()
    {
       // ......
    }
} //这里无须分号结尾

(2)命名空间定义可以不连续,可以写在不同的位置,甚至写在不同的源文件中。如果之前没有定义过该命名空间,那么这就相当于定义了一个新的命名空间;如果之前已经定义了该命名空间,那这就相当于打开已经存在的命名空间并为其添加内容。

(3)外界对命名空间中实体的访问方法:
使用两个冒号,“作用域运算符”:

命名空间名::实体名

例如希望在main函数中调用命名空间NMZhangSan中的radius函数:

//MyProject.cpp源文件代码如下
namespace NMZhangSan			//定义命名空间
{
	void radius()
	{
		printf("NMZhangSan::radius函数被执行.\n");
	}
}
int main()						//主函数
{
	NMZhangSan::radius();		//调用NMZhangSan命名空间下的radius函数
}

假如项目中还有另一个源文件MyProject2,其中有一个NMLiSi命名空间,

//MyProject2.cpp源文件代码如下
namespace NMLiSi		
{
	void radius()
	{
		printf("NMLiSi::radius函数被执行.\n");
	}
}

此时,希望也在main函数中调用NMLiSi命名空间下的radius函数,于是在main函数中增加如下代码:

NMLiSi::radius();		//调用NMLiSi命名空间下的radius函数

编译出错,无法调用成功。

为成功调用NMLiSi::radius,就需要对代码进行认真细致的组织。该如何进行源代码的组织呢?
(1)把函数声明,包括以后学习类,要把类的定义等内容放到一个头文件中。
这里新建立一个MyProject2.h的头文件,内容如下:

namespace NMLiSi
{
	void radius();			//函数声明
}

(2)在MyProject.cpp文件开头增加如下代码把MyProject2.h这个头文件包含进来:

#include "MyProject2.h"

在次编译链接整个项目,成功,并能够正确执行。

(3)至此,每次调用都要在函数名之前写NMLiSi::前缀,感觉比较多余。这种访问方法还可以通过使用 using namespace 变得更直接,这样就可以直接使用命名空间中的实体而不需要写前缀了:

using namespace 命名空间名字;

现在在MyProject.cpp源文件中的main函数之前加入如下代码:

using namespace NMLiSi;

此时,把main函数中的“NMLiSi::radius();”修改为“radius();”,发现也能正确地调用NMLiSi命名空间中的radius函数。

(4)在通过using namespace 使用了多个不同的命名空间时,如果不同命名空间中包含相同名字的函数,就会导致系统无法分辨到底调用哪一个命名空间中的函数。

using namespace NMLiSi;			//内部含有radius函数
using namespace NMZhangSan;		//内部也含有radius函数

因此:要么不要同时声明两个命名空间;要么不同命名空间中的函数不要同名;要么调用命名空间函数时使用带前缀的调用方法。

13.2.2 基本输入/输出

1.基本输出
在C语言中,通常会用到printf函数往屏幕上输出一条信息,但是在C++中通常不用printf进行输出,显得很不专业,而是用C++提供的标准库。

特别提醒:在学习C++语言的过程中,不要排斥C++标准库,不要把针对C++语言的学习和针对C++标准库的学习割裂开来,而是要把学习C++标准库当成学习C++语言的重要组成部分。从现在起,每学习一个标准库功能,就是一个新的收获,就往更高水平又迈进了一步。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++学习笔记(《C++新经典》基础部分) 的相关文章

随机推荐