C++学习笔记(一)
基础语法
if语句
查看if语句基本格式
1 | if (condition1) { |
for语句
查看for语句基本格式
在 C++ 中,for 循环是一种常用的控制结构,它允许你重复执行一段代码特定次数或者遍历一个序列(如数组、容器或字符串)。以下是 for 循环的基本使用格式:
- 标准的
for循环
1 | for (初始化表达式; 循环条件; 步进表达式) { |
- 初始化:在循环开始前执行一次,用于初始化循环变量。
- 循环条件:在每次迭代前检查,如果为真,则执行循环体内的代码。
- 步进表达式:在每次循环结束时执行,用于更新循环变量。
- 示例:遍历数组
1 |
|
- 范围
for循环(C++11 及更高版本)
1 | for (声明语句 : 序列) { |
- 声明语句:声明用于遍历序列的变量。
- 序列:可以是数组、容器或任何提供了迭代器的对象。
- 示例:遍历字符串
1 |
|
- 示例:遍历容器
1 |
|
- 注意事项
- 循环变量的作用域:在标准的
for循环中,循环变量的作用域仅限于循环内部。在范围for循环中,循环变量的作用域可以是循环内部或整个函数。 - 避免在循环条件中修改循环变量:这可能会导致循环行为异常。
- 使用范围
for循环:当你需要遍历容器或数组时,范围for循环可以提供更简洁和更安全的语法。
现在,让我们使用 for 循环来输出一个 LaTeX 格式的数学公式:
1 |
|
在这个例子中,我们首先输出了整个 LaTeX 格式的数学公式,然后使用范围 for 循环遍历字符串中的每个字符并输出它们。这样做是为了演示 for 循环的用法,实际上在控制台输出 LaTeX 代码不会渲染数学公式,你需要在 LaTeX 文档中编译它才能看到格式化后的公式。
递归
一步骤,让我们更清楚地理解递归的过程对于计算斐波那契数列的第n项
递归计算斐波那契数列的第 n 项的过程可以通过以下步骤详细描述:
基线条件:递归算法需要有基线条件来终止递归。对于斐波那契数列,基线条件是当
n为 0 或 1 时,函数返回 1,因为斐波那契数列的前两项都是 1。1
2if (n == 0) return 1;
if (n == 1) return 1;递归调用:如果
n大于 1,递归算法将问题分解成两个更小的子问题,即计算斐波那契数列的第n-1项和第n-2项。1
return Funct(n-1) + Funct(n-2);
递归展开:以下是递归调用的展开示例,它展示了递归是如何进行分解直到达到基线条件的。
假设我们要计算
Funct(5):Funct(5)调用Funct(4) + Funct(3)Funct(4)调用Funct(3) + Funct(2)Funct(3)调用Funct(2) + Funct(1)Funct(2)调用Funct(1) + Funct(0)Funct(1)返回 1 (基线条件)Funct(0)返回 1 (基线条件)
计算和返回:一旦到达基线条件,递归开始返回计算的值。每个函数调用都等待其子调用的结果来计算最终结果。
Funct(2)返回1 + 1 = 2Funct(3)返回2 + 1 = 3Funct(4)返回3 + 2 = 5Funct(5)返回5 + 3 = 8
最终结果:最终,最外层的函数调用
Funct(5)返回 8,这就是斐波那契数列的第 5 项。
递归过程的关键在于问题分解和子问题的解决,以及将子问题的解合并起来以解决原始问题。然而,递归方法计算斐波那契数列的一个缺点是它进行了大量的重复计算,这会导致性能问题,特别是对于较大的 n 值。为了提高效率,可以采用记忆化递归(使用缓存来存储已计算的值以避免重复计算)或者直接使用迭代方法。
orange,查看递归示例代码方法
1 |
|
编译工具
Dev-C++ 5.11 常用快捷键
Dev-C++ 5.11 提供了一系列代码编辑快捷键,以帮助开发者更快速、更高效地进行代码编写。以下是一些常用的代码编辑快捷键: 文件操作: 编辑操作: 代码注释: 代码缩进与格式化: 编译与运行: 调试操作: 其他: 这些快捷键可以帮助用户更高效地在Dev-C++环境中进行编程工作。需要注意的是,快捷键的具体组合可能会根据用户的个性化设置而有所不同。 查看快捷键
Visual Studio常用快捷键
在同一个项目文件下,多个c++文件中只能有一个main函数,否则系统会提示无法找到文件
查看快捷键
Visual Studio 2017 和 2019 为 C++ 开发提供了许多有用的快捷键,以下是一些常用的快捷键:
- 编码和编辑
- 格式化代码:
Ctrl + K, Ctrl + F - 注释/取消注释:
Ctrl + K, Ctrl + C(注释) 或Ctrl + K, Ctrl + U(取消注释) - 切换大小写:
Ctrl + Shift + U - 查找:
Ctrl + F - 查找和替换:
Ctrl + H - 在文件中替换:
Ctrl + Shift + H - 转到定义:
F12或Ctrl + 点击 - 查看引用:
Alt + F12 - 导航到:
Ctrl + G(转到行号) - 撤销:
Ctrl + Z - 重做:
Ctrl + Y - 剪切:
Ctrl + X - 复制:
Ctrl + C - 粘贴:
Ctrl + V - 删除行:
Ctrl + L - 删除到行末:
Ctrl + Delete - 插入行:
Ctrl + Enter - 智能提示:
Ctrl + Space - 参数信息:
Ctrl + Shift + Space - 代码片段:
Tab(在代码片段提示时)
- 格式化代码:
- 构建和调试
- 构建解决方案:
Ctrl + Shift + B - 清理解决方案:
Ctrl + Shift + E - 启动调试:
F5 - 逐行执行:
F10 - 逐语句执行:
F11 - 步出函数:
Shift + F11 - 运行到光标处:
Alt + F9 - 设置/清除断点:
F9 - 条件断点:
右键点击断点,选择“条件” - 断点日志:
右键点击断点,选择“日志” - 监视变量:在监视窗口中添加变量或表达式
- 构建解决方案:
- 查看和窗口管理
- 解决方案资源管理器:
Ctrl + Alt + L - 属性窗口:
Shift + F4 - 输出窗口:
Ctrl + Alt + O - 错误列表:
Ctrl + E, E - 任务列表:
Ctrl + Shift + K - 全屏:
F11 - 拆分窗口:
Ctrl + Shift + F3 - 切换拆分窗口:
Ctrl + F6或Ctrl + Tab - 预览代码:
Ctrl + Z(当在解决方案资源管理器中选择文件时)
- 解决方案资源管理器:
这些快捷键可以帮助你更高效地在 Visual Studio 中编写和调试 C++ 代码。Visual Studio 还提供了许多其他快捷键和功能,你可以通过查看 Visual Studio 的帮助文档或在网上搜索来发现更多。
第一章
c++是一种编译式的、通用的、大小写敏感的编程语言,完全支持面向对象开发模式
C++对c语言的增强表现在两个方
(1)在原来面向过程的机制上法,增加了c语言对类型的处理
(2)增加了面向对象机制
基本输入/输出流
说明: 输出输入10个数字
1)标准输入: cin>>变量1>>变量2>>……>>变量n
2)标准输出:cout<<表达式1<<表达式2<<……<<表达式n
3) 使用标准出入cin与标准输出cout前,要在程序的最前面包含1
2
3
4
5
6
using namespace std; //使用命名空间
// 如果不是该行的最后一个元素,输出一个空格作为分隔符,在一行内出入所有数组元素
if (j < j - 1) {
cout << " ";
}
4)换行操作:用语句cout<< endl;或者cout<<”\n”,不输入endl时不会自动换行
5)当连续从键盘上读取数据时,以空格、制表符tab键或enter键作为分隔符。
6)用户自己定义的数据类型,不能直接使用输入“>>”或输出“<<”,必须对输入输出符重载 基本输入输出示例
1
2
3
4
5
6
7
8
9
10
11
using namespace std;
int main(){
int a[10];
for(int i = 0;i<10;i++)
cin>>a[i];
for(int i = 0;i<10;i++)
cout<<a[i]<<" ";
cout<< "\n" ;
}
头文件和命名空间
1)头文件
| 常见头文件 | 表示 |
|---|---|
| 标准输入输出流 | iostream |
| 标准文件流 | fstream |
| 标准字符串处理函数 | string |
| 标准数学函数 | cmath |
程序员也可以编译自己的文件段,作为头文件反复调用
其他头文件:< iomanip >是C++标准库中的头文件,提供了一些格式化输出和输入的函数和操作符。
主要包括以下几个函数和操作符:
- setprecision(n):设置输出浮点数的精度为n位。
- setw(n):设置输出域宽为n个字符。
- setfill(c):设置输出时,如果域宽大于输出字符数,用字符c填充空余的位置。 eft和right操作符:分别设置输出左对齐和右对齐。
boolalpha和noboolalpha操作符:分别设置输出bool值为true/false或1/0。- hex、oct和dec操作符:分别设置输出16进制、8进制和10进制的整数。
- fixed和scientific操作符:分别设置输出为定点数和科学计数法表示的浮点数
- istream& ignore (streamsize n = 1, int delim = EOF); 其中,
n表示要跳过的字符数,delim是可选参数,表示要跳过的分隔符(默认为 EOF)。ignore() 会返回输入流对象,因此可以进行链式调用。- cin.ignore(numeric_limits< streamsize >::max(), ‘\n’); 其中,
numeric_limits<streamsize>::max()表示跳过输入流中的所有字符,直到遇到换行符为止
这些函数和操作符可以使得输出的格式更加规范和美观,提高代码的可读性和可维
2)命名空间
c++中为了避免名字定义冲突,特别引入“命名空间”的作用为了消除同名引起的歧义。在程序中使用标准程序库中的标识符时,要写语句“using namespace std;”.
函数返回值类型
在C++中,函数的返回类型可以有多种,以下是一些常见的返回类型:
基本数据类型:
int:整型char:字符型float:单精度浮点型double:双精度浮点型bool:布尔型
枚举类型:
- 枚举类型是用户定义的类型,它由一组命名的整数常量组成。
指针类型:
- 例如
int*,指向整型的指针。
- 例如
引用类型:
- 例如
int&,对整型的引用。
- 例如
数组类型:
- 例如
int[],表示一个整型数组。
- 例如
类和结构体:
- 例如
std::string或自定义的类和结构体类型。
- 例如
void:
void类型表示函数不返回任何值。
强制类型转换符
当不同类型的量进行混合运算时,系统自动进行合理的类型转换,也可以强制类型转换
1)将一种数据类型转换成另一种数据类型1
2
3
4
5
6
7static_cast<类型名>(表达式)
说明: static_cast 可以省略不写
oneint2 = static_cast<int>(oneDouble);
oneint2 = int(oneDouble);
oneint2 = (int)oneDouble; //圆括号
oneint2 = oneDouble; //自动类型转换
函数参数默认值
1)c++中,可以在声明函数时为形参制定默认值。调用函数时,从最左侧的参数开始调用 a=11b=22c=33 带默认值函数示例
1
2
3
4
5
6
7
8
9
10
11
12
13
using namespace std;
void func(int a = 11,int b = 22, int c = 33){
cout<<"a="<<a<< "b="<< b << "c="<< c <<"\n";
}
int main(){
func();
func(55);
func(77,99);
func(8,88,888);
return 0;
}
a=55b=22c=33
a=77b=99c=33
a=8b=88c=888
2)c++语言规定,定义函数时,为参数赋值,只能按照从后往前的顺序赋值,且在调用是也只省缺后面的连续若干个实参。
例子:1
2
3
4void dfi(int a = 2,double b = 3.0); //正确
void dfi(int a ,double b = 3.0); //正确
void dfi(int a = 2,double b); //错误
3)c++语言规定,在函数的调用处只能省缺后面的连续若干个实参,而且所有缺省的实参都必须有默认值。。
函数调用示例:1
2
3
4
5
6函数声明: void func(int a ,int b = 2,int c = 3)
函数调用:func(1,22,33); //正确
函数调用:func(); //错误
函数调用:func(10,20); //正确
函数调用:func(5,,9); //错误
4)c++语言规定,在指定默认值是不仅可以使用常数,还可以用任何有定义的表达式作为参数默认值
函数调用示例:1
2
3int Max(int m, int n)
int a,b
void func2(int x,int y = Max(a,b),int t = a-b){……}
5)函数声明没有函数体,表示有这个函数存在;函数定义有函数体,表示函数的具体实现;函数的默认值可以给到其中的一个,但是不能同时都给
引用和函数参数的传递
注意: 两种方式:传值与传引用
1、对象在引用前必须先初始化,声明中符号“&”的位置无关紧要。
2、不能通过常引用(const)去修改其引用变量的值。
3、const位于符号*的左侧,表示指针
4、const位于符号*的右侧,表示指
4、const位于符号*的左右两侧,表示指 查看教程
普通引用与常引用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15列:
//普通引用:
int x = 10;
int &a = x ; // a就是一个普通引用
int & a = x ; //正确
int a& = x ;//正确
//常引用:
const int &b = x ; // b就是一个常引用
a = 20; //则x = 20,b = 20
x = 30; //则a = 30,b = 30
b = 40; //错误
const int *pa2 = &a2; //指针pa2所指的数据是常量
int * const pa2 = &a2; //指针pa2是常量 ,所指数据为变量
const int * const pa2 = &a2; //指针pa2与所指的数据都是常量 引用在函数中的使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// 值传递
void SVal(int a,int b){
int tmp;
tmp = a; a = b; b = tmp;
cout <<"SVal()函数中:\t\ta = "<<a<<",b="<<b<<endl;
return;
}
// 引用传递
void SRef(int & a,int &b){
int tmp;
tmp = a; a = b; b = tmp;
cout <<"SRef()函数中:\t\ta = "<<a<<",b="<<b<<endl;
return;
}
内联函数
对需要频繁调用,且代码量少的函数,可以将其定义为内联函数。编译时,编译程序将整个函数体的代码复制到调用该函数的位置。
可以使用关键字inline将成员函数定义为内联函数。(凡是出现调动该函数的地方,编译程序自动将其装换为该函数的函数体,不再在程序执行时调动该函数,大大提高了效率)。
1 | 定义内联函数的格式如下: |
函数的重载
为同一个函数定义几个版本 1.参数表中对用参数类型不一样 1.两个函数 注意事项
满足下面一个条件便可以重载
2.参数表中参数个数不同;
3.参数表中不同类型参数的次序不同不能重载的情况
1
2
3float add(int ,float);
int add(int ,float); //错误!
2.函数采用1
2
3void print(double);
void print(double &); //不可以重载
3.函数调用可能会引发1
2
3int Sum(int a,int b,int c=0);
int Sum(int a,int b);
且函数调用语句为:Sum(1,2) //调用会产生二义性不可重载
4.其他存在赋值兼容的情况
指针和动态内存分配
1.指针:即指针变量,该变量存储的是一个地址,是该指针所指对象的首地址。1
2int a = 100,*pa = &a;
int s[10],ps =s; //指针ps指向数组s的首地址
2.动态分配1
2
3
4
5
6
7
8
9动态分配内存的一般格式为:
指针名 = new 类型名; //分配
delete 指针名; // 释放
当不再使用这个空间时,必须使用delete释放空间。
若使用new运算符动态分配一个数组,那么释放该数组时,
语句如下:
delete [] 指针
示例
1
2
3
4
5
6
7
8
9
10
11
12
13
using namespace std;
int main()
{
double *p; //声明double类型指针
p = new double[3]; //分配3个double类型存储空间
for(int i = 0;i<3; i++)
cin>>*(p+i); //将输入数据存储在指定地址中
for(int j = 0;j<3; j++)
cout<<*(p+j)<<" "; //将地址里的内容输出
delete []p; // 释放空间
}
用string对象处理字符串
查看教程
1.说明:
1)使用string对象,必须#include< string.h >头文件
2)string对象存储的是字符串的首地址,并非字符串本身;sizeof(string)在32位的Dev C++中是4,在64位的Dev C++中是8.
2.对象的操作:
1)string对象,可以使用cin和cout进行输入、输出
2)string对象之间可以相互赋值,也可以用字符串常量和字符串数组的名字对string对象进行赋值。
3)string对象之间可以比较大小1
2
3bool b; //声明布尔型变量b
string s1 = "China", s2 = "Ok";
b =s1>s2; //比较两个字符串首字母大小 变量b的值为0
4)string对象,可以使用“+”运算对字符串进行连接
3.string类中常用的成员函数:
| 函数 | 功能 |
|---|---|
| const char *c_str()const; | 返回一个指向字符串的指针,用于将string转换为const char* |
| int size() const; | 返回当前字符串的大小 |
| int length() const; | 返回当前字符串的长度 |
| bool empty() const ; | 判定当前字符串是否为空 |
| size_type find(const char *str,size_type index); | 返回str在字符串中第一个出现的位置(从index开始查找)如果没有找到返回 -1 |
| size_type find( char ch,size_type index); | 返回ch在字符串中第一个出现的位置(从index开始查找)如果没有找到返回 -1 |
| string & insert(int p,const string & s); | 在p位置插入字符串s |
| string &append(const string * s); | 将字符串s 连接到当前字符串的结尾处 |
| string substr(int pos = 0,int n = npos)const; | 返回从pos开始n个字符组成的字符串 |
示例
源码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using namespace std;
int main(){
string str;
if(str.empty())
cout<<"str is NULL."<<",length="<<str.length()<<endl;
else
cout<< "str is not NULL."<<endl;
str = str.append("abcdefg"); //将字符串连接到当前字符串的结尾
cout<<"str is"<<str<<",size = "<<str.size()<<str.length()<<endl;
cout<<"length"<<str.length()<<endl;
const char*p = str.c_str(); //p指向字符串str
cout<<"p = "<<p<<endl; //输出abcdefg
cout<<"find:"<<str.find("de",0)<<endl; //从str的第0查找字符串“de”,成功返回3
cout<<"find:"<<str.find("de",4)<<endl; //从str的第4查找字符串“de”,查找失败返回-1对应的无符号数
string str1 = str.insert(4,"123"); //重str的第4个位置插入“123”
cout<<str1<<endl;
return 0;
}
结果:
str is NULL.,length=0
str isabcdefg,size = 77
length7
p = abcdefg
find:3
find:18446744073709551615
abcd123efg
第二章
结构化程序设计
结构化程序设计的基本方法:采用自顶向下、逐步求精模块化的思想,将复杂的大问题层层分解为许多简单的小问题。
结构化程序设计的三种基本结构:顺序结构、选择结构、循环结构。
结构化程序设计的基本思想:
结构化程序设计的缺点:难以理解,难以扩充、难以纠错
面向对象的设计的概念和特点
1、概念 1.两种继承: 1.C++支持
面向对象技术将问题看成
对象 = 数据(属性) + 函数(行为)
类是对象的一个抽象、对象是类的实例化
2、特点(抽象、封装、继承和多态)
1)抽象:将同一类事物的共同特征概括出来,这个过程叫做“抽象”。
类:是对现实世界中客观事物的抽象。对于一个具体的类它有许多具体的个体,这些个体叫做对象。
对象:是系统中用来描述客观事物的一个实体,用对象名、属性操作三要素来描述对象。
2)封装:就是把对象的属性和操作封装结合成一个独立的单元。
封装的作用:数据和操作数据的函数紧密联系起来;将对象的一部分属性和函数隐藏起来,对外不可见,起保护作用;另一部分函数对外可见,作为对象进行操作的接口。
3)继承:在编写一个新类的时候以现有的类作为基础,使得到的新类从现有的类“派生”而来,从而达到代码扩充和代码复用作用。 考点
单一继承 与 多重继承
4)多态:不同的对象可以调用相同名称的函数,但可导致完全不同的行为的现象称为。多态性。利用多态性,程序中只需要进行一般形式的函数调用,函数的实现细节留给接收函数调用的对象,这大大提高了人们解决复杂问题的能力。 考点
编译时的多态与运行时多态
类的初步认识
- 类的基本概念
类:是具有相同属性和操作的一组对象的集合,它为属于该类的 全部对象提供了统一的抽象描述,其内部包括数据变量和成员函数两个主要部分。
类是一种用户自己构造的数据类型,
类要先声明后使用、是具有唯一标识的实体。 - C++语言中常用的数据类型有
整型、实型、字符型(这3种类型也被称之为简单数
据类型)、数组类型、布尔类型、枚举类型、结构体类型、公用体类型、指针类型、引用类参考链接
型等。
| 访问级别 | 访问控制修饰符 | 同类 | 派生类 | 外部类 |
|---|---|---|---|---|
| 公开 | public | √ | √ | √ |
| 受保护 | protected | √ | √ | × |
| 默认 | private | √ | × | × |
| 私有 | private | √ | × | × |
访问修饰符示例
1 |
|
Length of box:10
Width of box:10.3使用private的好处:1)有利于程序修改2)可以避免对象的不正确操作
类的示例剖析
注意:1、在c++中string关键字全小写,在java中String首字母大写 请输入学生的姓名生日,生日以年月日的次序输入;小明 2000 3 14
2、类名myClass,方法名myFunctiond都使用小驼峰表示,变流量使用全拼小写,常量使用大驼峰表示
3、在类中提前声明方法,在类外书写方法体,更清晰易渎,在类体外定义成员函数时使用 程序结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
using namespace std;
class myDate{
public:
myDate(); //构造函数
myDate(int,int,int); //带参数的构造函数
void setDate(int,int,int); //设置
void setDate(myDate); //设置
myDate getDate(); //获取 日期
void setYrar(); //设置
int getMonth(); //获取
void printDate() const; //打印日期
private:
int year,month,day;
};
myDate::myDate(){ // 构造函数
year =1970,month = 1,day = 1;
}
myDate::myDate(int y,int m,int d){ // 构造函数
year =y,month =m,day = d;
}
void myDate::setDate(int y,int m ,int d){ // 构造函数
year =y,month =m,day = d;
return;
}
void myDate::setDate(myDate oneD){ // 构造函数
year =oneD.year =oneD.month,day = oneD.day;
return;
}
myDate myDate::getDate(){ // 获取日期
return *this;
}
int myDate::getMonth(){ // 构造函数
return month;
}
void myDate::printDate() const{ // 构造函数
cout<<year<<"/"<<month<<"/"<<day;
return;
}
class Student{
public:
void setStudent(string,myDate); // 设置学生信息
void setName(string); // 设置学生姓名
string getName(); // 获取学生姓名
void setBirthday(myDate); // 设置学生生日
myDate getBirthday(); // 获取学生生日
void printStudent() const; // 设置学生生日
private:
string name;
myDate birthday;
} ;//string 系统定义好的类,myDate前面定义好的类
void Student::setStudent(string s,myDate d) { // 设置学生信息
name = s;
birthday.setDate(d);
return;
}
void Student::setName(string n ){ // 设置学生姓名
name = n;
return;
}
string Student::getName(){
return name;
}
void Student::setBirthday(myDate d){
birthday.setDate(d);
return;
}; // 设置学生生日
myDate Student::getBirthday(){
return birthday;
}; // 获取学生生日
void Student::printStudent() const{
cout<<"姓名"<<name<<"生日";
birthday.printDate();//调用myDate的成员函数
cout<<endl;
}; // 设置学生生日
int main(){
Student ss;
int y,m,d;
string name_;
cout<<"请输入学生的姓名生日,生日以年月日的次序输入;";
cin>>name_>>y>>m>>d;
ss.setStudent(name_,myDate(y,m,d));//调用成员函数
ss.printStudent();
return 0;
}
姓名小明生日3/1/14 使用引用方式驱动程序
1
2
3
4
5
6
7
8
9
10
11int main(){
Student ss;
int y,m,d;
string name_;
Student &sy = ss; //对象的引用
cout<<"请输入学生的姓名生日,生日以年月日的次序输入;";
cin>>name_>>y>>m>>d;
sy.setStudent(name_,myDate(y,m,d));//调用成员函数
sy.printStudent();
return 0;
}
标识符的作用域
1.函数原型作用域:在声明函数原型时形参的作用范围就是函数原型的作用域,也是c++中最小的作用域。
例:double area(double r)
r 的作用范围就在函数area形参列表的左右括号之间。
2.局部作用域:只在程序块内有效。
3.类作用域:在类X成员函数中可以直接使用成员m;在类外通过x.m、X::m或者ptr->m ,ptr为指向该类的指针。
4.命名空间的作用域:用于消除各大模块之间同名引起的歧义。在命名空间内部可以直接引用当前命名空间中声明的标识符,如需要引用其他空间命名的标识符使用以下格式:
命名空间::标识符
第三章
构造函数
1.使用构造函数创建指针:myDate *pd = new myDate();使用new创建对象,下面两种都是合法的:
myDate *pd = new myDate()
myDate *pd = new myDate
1)用户定义了构造函数,都会调用构造函数进行初始化。
2)用户未定义构造函数,
2.复制构造函数:
1)使用一个已存在的对象去初始化另一个正在创建的对象
2)复制构造函数的原型为:
类名::类名(类名&) // 对象的引用作为形参
或类名::类名(`const`类名` &`) //为了不改变原型对象,使用`const限制` 复制构造函数示例
1
2
3
4
5
6
7
8
9
10
11
12Student(); //在类中声明构造函数的
Student(const Student &s); //在类中声明复制构造函数的原型
Student:: Student(const Student &s){//复制构造函数的函数体
name = "copy"+s.name;
birthday = s.birthday;
}
void main(){
Student stud;//定义对象stud,并调用构造函数
Student stud2(stud); //定义对象stud2并调用复制构造函数初始化
Student ss[3]{Student(),stud,Student(stu)}}; //ss[0]调用构造函数,ss[1]与ss[2]调用复制构造函数初始化
析构函数
作用:在对象消失时,释放由构造函数分配的内存
在类体中的声明形式:~类名();
定义形式:类名::~类名(){ }
注意:
- 在
类中只能定义一个析构函数且不能指定参数,并对象生存周期结束时,系统自定调用。 - 系统会自动生成空的析构函数,使用
new运算符动态分配了内存空间,则在析构函数中应该使用delete释放掉这部分空间。 - 系统会按照
后创建先析构的顺序,可以使用delete调用析构函数改变顺序。
析构造函数示例
1 |
|
myDate构造函数1
Student构造函数2
姓名 Noname 生日1970/1/1
myDate构造函数1
Student构造函数2
myDate构造函数1
Student复制构造函数2
姓名 Noname 生日1970/1/1
姓名 copyNoname 生日1970/1/1
Student析构函数2
myDate析构函数1
Student析构函数2
myDate析构函数1
Student析构函数2
myDate析构函数1
注意:
在构造函数中初始化对象的变量:1
2
3
4Student::Student():name("Noname"),birthday(myDate()){
}
类的静态成员
- 静态全局变量:static修饰的、在所有花括号之外声明的变量,
其作用范围全局可见,整个项目内有效 - 静态局部变量:static修饰的、在块内定义的,
其作用范围从定义之处开始到本块结束为止 - 静态变量均存储在全局数据区,只初始化一次,如果未初始化系默认初始为0;
- 类的静态成员有两种:静态成员变量与静态成员函数,
静态成员变量不能在类体内赋值,应该在类外进行初始化,给静态成员变量赋初始值格式如下:
类型 类名:: 静态成员变量 = 初值;//不能有static- 在类体外定义成员函数时,前面不能加
static - 类的静态成员,被类的所有对象
共享注意:
静态成员函数不可以调用非静态成员
访问静态成员的一般格式:
类名:: 静态成员名
对象名 · 静态成员名
对象指针->静态成员名静态成员函数与一般成员函数的不同
1)可以不指向某个具体对象,只与类名连用
2)在没有建立对向前,静态成员就已经存在;
3)静态成员是类的成员,不是对象的成员;
4)静态成员为该类的所有对象共享,他们被存储在一个公共区域
5)没有this指着,只能通过对象名或指向对象的指针访问类的数据成员
6)静态成员函数不能被说明为虚函数
7)静态成员函数不能直接访问非静态函数
静态成员变量示例
1 |
|
静态成员函数示例
1 |
|
classA::num = 1
调用静态函数current_num = 1
obj.num 1
调用静态函数current_num = 1
classA::num = 4
调用静态函数current_num = 4
classA::num 5
调用静态函数current_num = 5
p->num 5
调用静态函数current_num = 5
变量及对象的生存期和作用域
生存期:是指所占据内存空间由分配到释放的时期。
作用域:仅仅在定义的代码块内有效。
常量成员和常量引用成员
1、 类的常量成员变量
定义
类的常量成员变量的一般格式:const 数据不类型
类常量成员变量= 表达式
类常量成员变量必须进行初始化,而且只能通过构造函数的成员初始化列表方式进行。
2、 类的常量对象
类的常量对象必须在
声明的同时进行初始化,而且不能被更新。定义常量对象的格式:const 类名 对象名(参数表);或
类名 const 对象名(参数表);
例:1
myDate const al(1997,12,20); //定义myDate类常量对象al 并初始化
常量对象只能调用常量成员函数不能调用非常量成员函数,普通对象可以调用所有成员函数常量成员函数与普通成员函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
using namespace std;
class Sample{
public:
Sample();
void getVlue() const;//常量成员函数
void getVlue() ;//非常量成员函数 (同名)
void priVlue() ;//非常量成员函数
void priVcon() const;//常量成员函数
};
Sample::Sample() {};//构造函数
void Sample::getVlue() const //常量成员函数
{
cout<<"常量成员函数" <<endl;
}
void Sample::getVlue() //非常量成员函数
{
cout<<"非常量成员函数" <<endl;
}
void Sample::priVlue() //非常量成员函数
{
cout<<"非常量成员函数priVlue()" <<endl;
}
void Sample::priVcon() const //常量成员函数
{
cout<<"常量成员函数priVcon()" <<endl;
}
int main(){
Sample o;
const Sample cono;
cout<<"cono\t";
cono.getVlue();//通过常量对象只能,调动常量函数
// cono.priVlue() ; //错误!不能调用非常量成员函数
cout<<"o\t";
o.getVlue(); //“同名”情况下,系统自动调用区别用
cout<<"o\t";
o.priVlue(); //调用普通函数
cout<<"o\t";
o.priVcon(); //调用常量成员函数
return 0;
}cono 常量成员函数
o 非常量成员函数
o 非常量成员函数priVlue()
o 常量成员函数priVcon()
3、常量函数
在类体内定义常量函数格式:
类型标识符 函数名 (参数列表) const{….//函数体}
在类体内声明,体外定义格式:
声明形式: 类型标识符 函数名 (参数列表)const;
定义形式: 类型标识符 类名::函数名(参数列表) const;
{….//函数体}
4、常引用作为函数参数
使用引用作为函数参数,传送的是地址,所以形参改变,则实参也跟着改变,但如果不希望函数改变对象的值,就要使用常引用作为参数,
例如:1
void Display(const double& r){cout<<r<<endl} //Display是能使用而不能改变r所引用的对象。
常量成员变量及常量成员函数的使用
1 |
|
conMbr = 123,Mbr200
调用非常量函数
ob2.getConst() = 0
在processConst函数中非常量—
x = 2*conMbr +1 = 1
Mbr = 101
调用常量函数
ob3.getConst() = 20
在processConst函数中非常量—
x = conMbr +1 = 21
Mbr = 200
常引用型成员变量
1 |
|
24
f.num= 100 f.ref =4 f.value =4
成员对象和封闭类
1、在定义封闭类的构造函数时,需要添加初始化列表指明要调用成员对象的那个构造函数。
在封闭类构造函数中添加初始化列表格式:
封闭类名::构造函数名 (参数表):成员变量1(参数表), 成员变量2 (参数表)····{····}
例:1
Student::Student(string n):name(n) ,birthday(myDate()){}
注意:
1) 执行封闭类的构造函数时,先执行成员对象的构造函数,然后再执行封闭类自己的构造函数。
2) 成员对象的构造函数的执行次序与成员对象在类定义中的说明次序一致,与在构造函数初始化列表中出现的次序无关
3) ;当封闭类消亡时先执行封闭类的析构函数,然后再执行成员对象的析构函数,析构函数先构造后析构
封闭类构造函数的初始化列表
1 |
|
price= 48900 getRadius = 17 getWidth = 2552、封闭类的复制构造函数
如果封闭类的对象是用默认复制构造函数初始化,那么他包含的
成员对象也会用复制构造函数初始化
封闭类的复制构造函数
1 |
|
default
copy
友元
1、 友元机制是对类外一些函数打开的一个特殊通道,授权他们能够访问本类的私有成员变量。
2、 友元机制破坏了类的封装性和信息隐藏,但有助于数据共享,能够提高程序的效率
3、 友元机制包括友元函数和友元类
友元函数:
在定义一个类的时候,可以把一些函数(包括
全局函数和其他类成员函数)声明为“友元”,这样这些函数就成为了友元函数类中声明友元函数的格式:
friend 函数类型 函数名(参数表); //
针对全局函数
friend 函数类型 函数所在类名::函数名(参数列表);注意:
友元函数可以在类中私有或公有部分通过关键字friend
声明或定义,但如在类中声明,而在类外定义,就不能再在类外使用friend关键字。友元函数的优点
- 友元函数应被看做
类接口的一部分,使用它的主要目的是提高效率,因为它可以直接访问对象的私有成员,从而省去调用类的相应成员函数开销。- 类的设计者不必考虑好该类的各种使用情况之后再设计这个类,而是可以根据需要,通过用友元来增加类的接口。
友元函数声明
1 |
|
Pixel:(0,0)
Pixel:(10,10)
(p1,p2)之间的距离 =14.1421
从友元函数中输出——
p.x =0 p.y =0
p.x =10 p.y =10
友元类
如果将一个类B说明为另一个类A的友元类,则类B中的所有函数都是类A的友元函数
友元类的关系是单向的,且不可出传递
除非必要一般不使用友元类在类定义中声明友元类的格式
friend clsaa 类名
友元类示例
1 |
|
(1,2)+(3,4)=(4,6)
this指针
1、当一个承运函数被调用时,系统将自动向它传递一个隐含参数,该参数是一个指向调用该函数的对象指针,名为this指针,从而使成员函数知道该对那个对象进行操作。
2、使用this指针,保证了每个对象可以拥有自己的数据成员,但处理这些数据成员的代码却可以被所有的对象共享,从而提高了程序的安全性和效率。
3、this指针式实现封装的一种机制,它将对象和该对象调用的成员函数链接在一起,从而在外部看来,每个对象都拥有自己的成员函数。
注意:
除非形参的名字与成员变量的名相同。一般情况下都省略掉符号
this->,而让系统进行默认







