C++学习回顾(1)

C++学习回顾(1)

对本文C++学习时经常学完就忘的知识点进行记录(第一部分)
包含编码、函数、类与对象、数据的共享与保护等内容
本文主要参考了郑莉著的《C++语言程序设计(第四版)》

1 编码

简述:对于正数来说,原码反码和补码都是一致的,最左侧一位为0,表示为正数。负数原码最左侧为1,负数的反码则是原码除符号位其余位取反,负数的补码则是在反码的基础上再加1,即最右侧位加1,依次进位。
教材定义:
原码:将符号位数字化为0或者1,数的绝对值与符号一起编码,即所谓的“符号-绝对值表示”的编码,称为原码。
反码:负数的反码的符号位与原码相同(仍用1表示负数),其余各位取反。
补码:对于一个负数,其补码由概述反码的最末位加1求得。

面向对象的基本概念

封装
封装是把对象的属性和服务结合成一个独立的系统单位,并尽可能隐蔽对象的内部细节。例如,类和函数都可以理解为封装,内部信息隐藏,仅通过公有成员函数或形参与外部联系实现功能。
继承
特殊类的对象拥有一般类的全部属性和服务,称作特殊类对一般类的继承。继承一般是对父类功能进行扩充或者修改。
多态性
多态性是指在一般类中定义的属性和行为,被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。多态可以增加程序的可读性,例如可以通过函数重载将具有相似功能的函数同名,简化开发流程。多态的方法有重载,虚函数等。

具有相同属性和服务的一组对象的集合。
对象
对象不仅定义了变量的类型,还定义了可以对变量进行的操作。

2 C++概述

C++特点
C++尽量兼容C,支持面向对象,当然你也可以不用。
C++标识符命名规则:可以以大小写字母或者下划线开头,不能用数字开头,数字可以用在非首位。
C++基本数据类型char型(字符型)从本质上来说也是整数类型,长度为1字节,通常用来存放字符的ASCII编码。
float可以保存7为有效数字,double可以保存15位有效数字。
常量:分为整型常量,实型常量,字符常量,字符串常量“a”与字符常量’a’不同,字符串常量“a”末尾添加’\0‘结尾标记。
声明与定义
声明一个变量只是将变量的标识符等有关信息告诉编译器,使编译器“认识”该标识符,但是声明并不一定引起内存的分配。而定义一个变量意味着给变量分配内存空间,用于存放对应类型的数据,变量名就是对相应内存单元的命名。但是在C++中大多数情况下,变量的声明也就是变量的定义,只有声明外部变量时例外。
符号常量
除了直接用文字表示的常量,也可以位常量命名,这就是符号常量。
符号常量在使用前一定要声明,符号常量在声明时一定要赋值(初始化),初始化之后就不能再更改它的值。
条件表达式
C++中的唯一三目运算符——条件运算符“?”
表达式1? 表达式2:表达式3
先求解表达式1,若表达式1==true,则求解表达式2;否则求解表达式3

cout<<(score>=60? "pass":"fail");

混合运算时的数据类型转换
隐含转换:低精度类型数据转换为高类型数据。
显示转换:

类型说明符(表达式)
float z = 7.56;
int a =  int(z);  //C++风格 C语言风格(int)z也可以

算法基本控制结构
顺序结构,选择结构和循环结构
switch语句
switch可以实现选择结构,适用于每一次都是判断同一表达式的值的情况。
注意每个case语句仅是一个程序的入口标号,case并不决定执行从终止点,因此每个case分支最后都应再加一个break语句,用来结束整个switch结构。
continue语句可以出现在循环体中,其作用是结束本次循环,接着开始判断决定是否继续执行下一次循环。
goto语句打破了程序的结构性,一般不用,但可以用于跳出多层循环的结构中。
自定义数据类型
自定义数据类型有:枚举类型、结构类型、联合类型、数组类型、类类型。
枚举类型enum

enum 枚举变量名 {变量值列表}enum Weekday {SUN,MON,TUE.WED,THU,FRI,SAT};

枚举元素按常量处理,不能复制
可以改变枚举元素的默认值

enum Weekday {SUN=7,MON=1,TUE.WED,THU,FRI,SAT};

整数值不能直接赋给枚举变量,需要进行强制类型转换。
typedef
typedef用于将一个标识符声明成某个数据类型的别名,然后将这个标识符当作数据类型使用

typedef 已有数据类型 新类型名表

typedef double Area,Volume;
Area a;
Volume v;

3 函数

函数基础知识
调用其他函数的函数称为主调函数,被其他函数调用的函数称为被调函数。
main函数也可以有形参,其形参也称为命令行参数。
如果希望在定义一个函数前调用它,则需要在调用函数之前添加该函数的函数原型声明。

声明方法:
类型说明符 函数名(含类型说明的形参表);
调用方法:
函数名(实参表); //也可以是表达式形式,需要有一个明确的返回值

随机数rand

int rand(void); //产生伪随机数函数,种子不同产生的伪随机数不同,默认种子为1
//种子设置方法
unsigned seed;
cin>>seed;  //输入随机数种子
srand(seed);  //将种子传递给rand()

递归调用
函数可以直接或者间接的调用自身,称为递归调用。
第一阶段:递推,将原问题不断分解为新的子问题,逐渐从未知向已知推进,最终达到已知的条件,即递归结束的条件,这时递推阶段结束。
第二阶段:回归,从已知的条件出发,按照递归的逆过程,逐一求解回归,最终达到已知的条件,即递归结束的条件,这时递推阶段结束。
参数传递
值传递是函数调用时用实参来初始化形参,值传递是单向的。
引用传递:定义引用类型的形参,参数传递是双向的。
引用:是一种特殊的变量,可以被认为是另一个变量的别名,声明一个引用时,必须同时对它进行初始化。
内联函数
内联函数不是在调用的时候发生控制转移,而是在编译时将函数体嵌入在每一个调用处。
解决了函数调用降低程序执行效率的问题。
内联函数一般应该是比较简单的函数,否则会造成代码膨胀,增大开销。

inline double calArea(double radius){
	return PI*radius*radius;
}

带默认形参值的函数
函数在定义时可以预先声明默认的形参值。
有默认值的形参必须在形参列表的最后。
在相同的作用域内,不允许在同一个函数的多个声明中对同一个函数的默认值重复定义,即使前后定义的值相同也不行。

int add(int x, int y = 5, int z = 6);  //有默认值的形参放在后面

int add(int x /* = 5 */,int y /* = 6 */ ){   //避免重复定义
	return x+y;
}

函数重载
两个以上的函数,具有相同的函数名,但是形参的个数或者类型不同,编译器根据实参和形参的类型及个数的最佳匹配,自动确定调用哪一个函数,这就是函数的重载。
注意不要将不同功能的函数定义为重载函数。
当使用具有默认形参值的函数重载时,需要注意防止二义性,例如:

void fun(int length , int width = 2, int height = 33);
void fun(int length);

fun(1); //出现二义性,不知道是省略参数还是调用第二个重载的函数

C++系统函数
数学函数#include <cmatch>
类似的还有:

cstdlib cstdio ctime

在C++中尽量不要使用.h后缀的头文件。
局部变量与全局变量
局部变量:变量的定义放在函数之内。
局部变量只在调用它所在的函数时才会生效,一旦函数返回后就会失效,很多局部变量的生存周期远小于整个程序的运行周期。
函数形参与局部变量相似,都不能像全局变量那样用固定地址加以定位,而需要存储在一种特殊的结构中,这就是栈。
函数部分总结
在面向对象的程序设计中,函数是功能抽象的基本单位,函数也是C++中子程序的体现。函数可以提高代码的复用率,使用时只需要关心函数的功能和使用方法而不必关心函数功能的具体实现。(类似于封装的思想)
重载函数根据形参进行区分,同名的重载函数其形参类型或个数必须不同。

4 类与对象

抽象
面向对象的方法中的抽象,是指对具体问题(对象)进行概括,抽出一类对象的公共性质并加以描述的过程。

数据抽象:
int hours,int minute,int second
功能抽象:
showTime(),setTime()

封装
封装就是将抽象得到的数据和行为(功能)相结合,形成一个有机的整体,也就是将数据与操作数据得到的函数代码进行有机的结合,形成“类”,其中的数据和函数都是类的成员。

class Clock
{
	public:
		void setTime(int newH,int newM,int newS);  //外部接口
		void showTime();
	private:
		int hour,minute,second;
};

继承
C++中允许在保持原有类特性的基础上,进行更具体更详细的说明。
多态
多态性是指一段程序能够处理多种类型对象的能力。在C++语言中,这种多态性可以通过强制多态、重载多态、类型参数化多态、包含多态4种形式来实现。
类的对象
类是一种抽象,描述了一类事物的共同属性和行为。
类的对象是该类的某一特定实体(也称实例)。
在类的外部表只能访问到类的公有成员;在类的成员函数中,可以访问到类的全部成员。

void Clock::setTime(int newH,int newM,int newS){  //加以类名进行限制
	hour = newH;  //hour minute second 都是私有成员,在类内可以直接访问
	minute = newM;
	second = newS;
}

在类中说明函数原型,可以在类外给出函数的实现,并在函数名前使用类名加以限定。也可以直接在类中给出函数体(如果函数体较小的话),形成内联函数,并且不用写inline(隐式声明),在类外实现内联函数时显式声明时需要写inline。
结构体与类
一般使用结构体存放数据,使用类来存放数据类型。
类用来定义数据结构和数据上可以进行那些操作。
结构体中默认为public,类中默认为private。
构造函数
构造函数的作用是在对象被创建时使用特定的值构造对象,或将对象初始化为一个特定的状态。
构造函数在对象被创建时自动调用,完成对象初始化。
构造函数的函数名与类名相同,并且没有返回值,通常声明为公有。
默认构造函数无需提供参数,在不写构造函数的情况下,编译器一般会自动生成一个默认构造函数。
构造函数也可以重载,一般都要重载一个默认构造函数。
拷贝构造函数
具有自行复制本类对象的能力。
具有一般构造函数的所有特性,其形参是本类对象的引用。其作用是使用一个已经存在的对象(由拷贝构造函数的参数指定),去初始化同类的一个对象。
复制构造函数会被调用的三种情况:
(1)当用类的一个对象去初始化该类的另一个对象时。
(2)如果函数的形参是类的对象,调用函数时,进行形参和实参的结合时。
(3)如果函数的返回值是类的对象,函数执行完成返回调用者时。
析构函数
释放占用的资源,若不定义编译器也会自动生成。
析构函数在对象的生存期即将结束的时刻被自动调用。
析构函数没有返回值,并且不接受任何参数。
类的组合
类中的成员数据是另一个类的对象。(个人理解和基本数据类型使用差不多)
类的组合中,每个类的对象的初始化都是由自己类的构造函数负责的。
调用内嵌对象的构造函数,调用顺序按照内嵌对象在组合类的定义中出现的次序,与初始化列表中顺序无关。
析构函数的调用顺序与构造函数正好相反。

class Line{
	public:
		Line(Point xp1,Point xp2);
		Line(Line &l);
		double getLen(){return len}
	private:
		Point p1,p2;
		double len;
};
//组合类的构造函数
//类名::类名(形参表):内嵌对象1(形参表),内嵌对象2(形参表),...{类的初始化}
Line::Line(Point xp1.Point xp2):p1(xp1),p2(xp2){
	cout<<"";
}

组合类的拷贝构造函数

Line Line(Line &l):p1(l.p1),p2(l.p2){
	cout<<""<<endl;
	len = l.len;
}

前向引用声明
类的定义应先定义后使用,但是当存在两个类互相引用的情况时,即循环依赖,可以使用前向引用声明解决。
UML类图
UML(Unified Modeling Language,统一建模语言)。
(不做重点)
联合体
适用情况:一组数据中,任何两个数据不会同时有效。
联合体的全部数据成员共享同一组内存单元。
联合体是一种特殊形态的类。

union 	Mark{
	char grade;
	bool pass;
	int percent;
};

联合体不能继承,不支持包含多态。可以不声明名称,称为无名联合体。

5 数据的共享与保护

类作用域
类X的成员m具有类作用域,程序中访问对象成员的基本方法是X.m或者X::m,X::m的方式用于访问类的静态成员。
也可通过ptr->m的方式访问,其中ptr为指向X类的一个对象的指针。
命名空间作用域
程序开发时不同模块中的类和函数之间可能会发生重名,用命名空间进行限制。
类似于上海市南京路和武汉市南京路。

namespace 命名空间名{
	命名空间内的各种声明(函数声明、类声明、...}
若引用其他命名空间中的标识符
namespace SomeNs{
	class SomeClass{...};
};
SomeNs::SomeClass obj1;  //声明一个SomeNs::SomeClass型的对象obj1

可见性
在这里插入图片描述
程序运行到某一点,能够引用到的标识符,就是该处可见的标识符。
外层标识符在内层不可见,外层会被隐藏。
静态生存期
如果对象的生存期与程序的运行期相同,则称它具有静态生存期。
在命名空间作用域中声明的对象都是具有静态生存期的。
如果在函数内部的局部作用域中声明静态生存期的对象,需要使用static,那么它的值在每次函数调用时都共享,不会随着函数的调用产生副本。
类的静态成员
模块见对内存中数据的共享是通过函数之间的数据共享实现的,其中包括两个途径——参数传递和全局变量。
静态成员可以解决同一个类的不同对象之间数据和函数共享问题。
静态数据成员
例如统计雇员总数(类属性),类的普通数据成员无法解决,则需要静态数据成员。
非静态数据成员——实例属性
静态数据成员——类属性
静态成员由该类的的所有对象共同维护和使用,从而实现了同一类的不同对象之间的数据共享。
类属性是描述类的所有对象共同特征的一个数据项,对于任何对象实例,它的属性值是相同的。

静态数据成员的声明
static int count;
静态数据成员的使用
int Point::count = 0;

静态函数成员

static void showCount(){
}

//使用
Point::showCount();

类的友元(友元函数)
友元函数是在类中用关键字friend修饰的非成员函数。
友元函数可以是一个普通的函数,也可以是其他类的成员函数,在它的函数体内可以通过对象名访问类的私有和保护成员。
友元函数的声明是在要使用的类的public中声明的,加friend。
友元类:若A类为B类的友元类,则A类的所有成员函数都是B类的友元函数,都可以访问B类的私有和保护成员。
注意:友元关系不能传递,友元关系是单向的,友元关系是不被继承的。
常对象
常对象的数据成员值在对象的整个生存期间不能被改变。
常对象必须进行初始化,并且不能被更新。

//声明常对象
const A a(3,4);  //a是常对象,并且不能被更新

常成员函数
使用const关键字修饰的函数称为常成员函数

//常成员函数
类型说明符  函数名(参数表) const

常对象只能调用常成员函数,而不能调用其他的成员函数。(常对象唯一的对外接口方式)
在常成员函数调用期间,目的对象都被视为常对象,因此常成员函数不能更新目的对象的数据成员。
const关键字可以用于对重载函数的区分

void print();
void print() const;  //对print的有效重载

常数据成员
在类中声明了常数据成员后,在任何函数中都不能对该成员进行赋值。

...
	private:
		const int a;  //常数据成员
		static const int b;  //静态常数据成员

常引用
常引用所引用的对象不能被更新。
常引用绑定到常对象,不能对基本数据类型的引用数据赋值,不能对类类型的引用修改数据成员。
编译预处理

//head.h
#ifndef HEAD_H
#define HEAD_H
...
class Point{
	...
}
...

首先判断HEAD_H是否被定义过,若为定义过则编译下面的程序段,并对标识符HEAD_H进行宏定义,标记此文件已经参加过编译。避免了对同一类的重复定义。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值