C++ Primer (暂时完结)
C++ Primer
- C++ 预备知识
- 泛型编程
- 第二章 开始学习C++
- 2.1.3 C++预处理器 和iostream 文件
- 名称空间
- 第二章 输出输入
- 输入
- 类的简介
- 2.4 函数
- 函数变体
- 自定义函数
- 编程练习
- 第三章 处理数据
- sizeof运算符
- 整型字面值
- C++ 如何确定常量的类型
- bool类型
- 3.3浮点数
- C++ 算术运算符
- 复合类型
- 4.1 数组
- 字符串
- string 类简介
- 4.5 共用体
- 4.6 枚举
- 4.7 指针和自由存储空间
- 指针,数组,指针算术
- 类型组合
- 数组的替代品
- 循环
- 第八章 函数探幽
- 8.2 引用变量
- 单独编译
- 存储秩序性,作用域和链接性
- 使用C++ 11 中的auto
- 静态持续性,内部链接性
- 说明符和限定符
- 函数和链接性
- 语言的链接性
- 存储方案和动态分配
- 9.3 名称空间
- 第十章 类和对象
- 10.2.3 实现类成员函数
- 10.2.4 使用类
- 类的构造和析构函数
- 10.3.4 析构函数
- 10.4 this指针
- 10.5 对象数组
C++ 预备知识
面向对象的编程(OOP)
什么是类,什么是对象
类包含 数据和操作
泛型编程
独立于特定的数据类型,
和数据类型无关,不管你是什么数据类型,只实现这个功能
第二章 开始学习C++
main 函数框架
g++是编译c++工具的
任何一个程序的开始都是从main开始
单片机可以不用main,动态链接库也可以不用main
注释
//两个斜线,单行注释
/**/ 多行注释
2.1.3 C++预处理器 和iostream 文件
#include <iostream>
using namespace std:
想要输入输出,就要有这两个
我包含了iostream文件,iostream里面所有的文件都会被包含在里面~
input output 流
想调用c库的话,前面加c 把点h去掉
名称空间
using 编译指令
如果我们想要有两个封装好的函数
两个,都有wanda() 函数
我们到底用哪个?
我们使用这个就可以找到具体的一个
如果不加using namespace的话,那就需要std:: 这样
然后加了的话,就会默认来自于std这个名称空间
这样的话,我们只会使用一点点,
声明之后,只开放了std的方法 count endl cin,这仨而且之后都可以随便使用
第二章 输出输入
输出流,将字符串流到输出
右侧信息插入到输出流中
运算符重载,
这两个运算符相同
多个符号,编译器会进行识别
endl控制符
end line
结束这一行
作用是为了重启一行
换行符
cout << "" << endl
规范的书写格式
c++源码风格
程序清单2.2
#include<iostream>
int main() {
using namespace std;
cout << "hello world\n";
cout << endl;
return 0;
}
C++ 首次使用前进行定义即可
#include<iostream>
int main() {
using namespace std;
int carrots;
carrots = 25;
cout << carrots << endl;
int c = 10;
cout << c << endl;
return 0;
}
打印的是字符串25 在内存中是存的11001 数字
cout 会字符串输出
#include<iostream>
int main() {
using namespace std;
int carrots;
carrots = 25;
cout << carrots << endl;
int c = 10;
cout << c << endl;
cout << "i have" << c << "is" << carrots << endl;
return 0;
}
输入
cin 输入流
#include<iostream>
int main() {
using namespace std;
int carrots;
cout << "hello can you guess" << endl;
cin >> carrots;
cout << "noooooo " << carrots << endl;
return 0;
}
一行比较长 可以这么写
类的简介
就相当于是一个数据类型了
数据和方法对吧,和java一样的
使用对象内的方法,也可以使用运算符重载
也就是<<
将信息传递给输出流对象
2.4 函数
有返回值的函数
例如那个sqrt() 函数
x = sqrt(6.25)
这个是已经写好的函数,
求平方根
传参的类型,返回的类型,
必须要知道这两个
缺少类型就报错了
说明他返回就是double
函数声明,带分号
提供原型,有两种方法
第二种方法更好,
函数原型在main前面
#include<iostream>
# include<cmath>
int main() {
using namespace std;
int carrots;
cout << "hello can you guess" << endl;
cin >> carrots;
cout << "noooooo " << carrots << endl;
double area;
cout << "Enter the floor area, in square feet,of your home:";
cin >> area;
cout << sqrt(area);
return 0;
}
函数变体
函数带多个参数
pow() 求几次方
rand () 不带参数的函数
bucks () 函数可以i没有返回值
没返回值不带参数
标准库中的函数~
自定义函数
#include<iostream>
# include<cmath>
void simon(int n);
int main() {
using namespace std;
simon(3);
return 0;
}
void simon(int n) {
using namespace std;
cout << "Simon says touch your toes " << n << " times." << endl;
}
带返回值的参数
#include<iostream>
# include<cmath>
void simon(int n);
int stonetolb(int sts);
int main() {
using namespace std;
cout << "Enter the weight in stone:";
int stone;
int pounds;
cin >> stone;
pounds = stonetolb(stone);
cout << pounds << endl;
return 0;
}
void simon(int n) {
using namespace std;
cout << "Simon says touch your toes " << n << " times." << endl;
}
//1 stone = 14 lbs
int stonetolb(int sts) {
int pounds = 14 * sts;
return pounds;
}
编程练习
#include<iostream>
# include<cmath>
using namespace std;
int hiahia(long x);
int main() {
cout << "Wum1ng " << "Peking" << endl;
long x;
int c;
cin >> x;
c = hiahia(x);
cout << c;
return 0;
}
int hiahia(long x) {
return x * 220;
}
第三章 处理数据
C++原生带着,内置的数据类型
基本数据类型,|复合数据类型
整形 浮点型 | 字符串,数组,结构体
简单变量
int braincount;
braincount = 5;
braincount 标记名称
变量名
字母数字下划线
不能数字开头
没有关键字
两个下划线,一个下划线,编译器保留使用,
区分大小写的
他存放的只是一个整数的子集
基本整形
-
char
-
short
-
int
-
long
-
long long
直接声明就可以
sizeof运算符
求在内存空间中的占用
定义常量 我们 一般全用大写~
头文件limits
包含一些宏定义
初始化
声明和赋值合并在一起
也可以用圆括号进行赋值
也可以使用{} 花括号初始化器
可以应用于任何的数据类型
无符号类型
最大值会扩大
让他们均+1 然后会发生越界
整型字面值
十进制,十六进制,八进制
cout 默认是输出的十进制输出
切换cout
然后是各个进制的
C++ 如何确定常量的类型
可以添加后缀
L ul ull
char类型,字符和小整数
char其实就是整形,他会存储成整型,只不过会对应一个表而已
一个字节就够了 2^8
ASCII
输入一个字符
cin 和cout
可以看出来,是77 同时 是M
如果我们+1 就会变成 78 也就是N
类里有变量,函数,我们需要访问对象对吧,
cin,cout 可以访问类内的函数
我们调用 cout 的put函数试试
转义字符
转义序列使用十六进制
bool类型
bool 类型转换成了int 也就是01转换
const 限定符
定义为了常量
不允许被修改
字母都大写的话,一般就是去使用#define
一般使用
const int xx = 111;
这样好
只希望某个常量在某个中实现,我们用const
使用const 不用define
3.3浮点数
E表示法
setf()
迫使输出定点表示,防止转换为E表示法
迫使显示后六位
cout默认打印后六位
cout会删除结尾的0
#include<iostream>
# include<cmath>
#include<climits>
using namespace std;
int main() {
cout.setf(ios_base::fixed, ios_base::floatfield);
float tub = 10.0 / 3.0;
const float million = 1.0E6;
cout << "tub = " << tub << endl;
return 0;
}
这里是带乘法的
#include<iostream>
# include<cmath>
#include<climits>
using namespace std;
int main() {
cout.setf(ios_base::fixed, ios_base::floatfield);
float tub = 10.0 / 3.0;
const float million = 1.0E6;
cout << "tub = " << tub << endl;
cout << "A million tubs " << million * tub << endl;
return 0;
}
这里已经出现问题拉
后面都是0了
因为float精度达不到
我们使用double 保证了精度
#include<iostream>
# include<cmath>
#include<climits>
using namespace std;
int main() {
cout.setf(ios_base::fixed, ios_base::floatfield);
float tub = 10.0 / 3.0;
const float million = 1.0E6;
cout << "tub = " << tub << endl;
cout << "A million tubs " << million * tub << endl;
double mint = 10.0 / 3.0;
cout << mint * million;
return 0;
}
浮点数的优缺点
运算的时候,浮点数运算会降低
a和b差1.0 但是 相减为0,精度降低了
float double 精度
浮点数如何存储呢?
单精度 32bit
double 双精度 64 bit
都要遵循 IEEE 标准,任意一个浮点数都是以科学计数法来表示
二进制的科学计数法
例如 8.25
整数+小数
1000. 01
0.25 * 2 =0.5 取处整数0
0.5 * 2 = 1 取出整数 1
1000.01转换为科学计数法,
1.00001*2^3
整数部分一定是1
计算机存储科学计数法,有符号的
符号正负(1 bit)
正数 0 负数 1
2^3 2^-3
因为要表示正负次幂,所以
2^(127+3)
计算机中存储浮点数,
一共32位,小数部分23位
精度是6位-7位,说的是十进制,2^23次约等于 10^6.923
符号(1位)+指数位(8位)+小数部分(0001000000000000000)
double类型,小数部分52个
C++ 算术运算符
求加减乘除
#include<iostream>
# include<cmath>
#include<climits>
using namespace std;
int main() {
float hats, head;
cout.setf(ios_base::fixed, ios_base::floatfield);
cout << "Enter a number:";
cin >> hats;
cout << "enter another number : ";
cin >> head;
cout << "heat= " << head <<"\n"<< "hats" << hats << endl;
;
return 0;
}
很明显,加出来不对
位数会一直往下增加
浮点数他要变二进制,小数一直×2
这行注释掉,就对了
四舍五入之后,才会对,之前是强制显示后六位
加减乘除都会有这个问题
float类型,真不行
我们要使用double类型
整数除法
向上转数据类型
位数加长,默认转为了double类型的除法
强制转float的话,加一个F
复合类型
4.1 数组
数组存相同的数据类型
数组中的内容在内存中是连续排列的
这三个点必须要有
short months[12]
声明通用通用格式
typeName arrayName[arraysize]
里面必须存放的是常量
数组中的编号从0开始~
程序员要确认好数组下标不越界
#include<iostream>
# include<cmath>
#include<climits>
using namespace std;
int main() {
int yams[3] = {7,8,6};
int yamscosts[3] = { 20,30,5 };
cout << "The total yams = " << yams[0] + yams[1] + yams[2] << endl;
cout << "The package with" << yams[1] << "yams cost " << yamscosts[1] << endl;
return 0;
}
数组初始化规则
定义的时候才能给值
一小部分初始化,其他都为0
也可以为空,编译器会自动计算个数
short things[] = {1,5,3,8}
变量类型缩窄
其实说白了就是一个变量赋值给另一个变量的时候发生溢出的情况,万一发生了缩窄转换,程序一般是不会报错的,这将非常不利于bug调试,因此要尽可能避免它。话不多说,看看例子吧。
#include <iostream>
using namespace std;
int main()
{
int a = 5000000; //-2147483648~2147483647
short int b = a;
cout << b << endl;
return 0;
}
可以很明显地看到结果不是我们想要的,甚至不符合溢出。那么怎么避免变量类型缩窄转换呢?C++11
提供了初始化列表就可以避免这一问题。
#include <iostream>
using namespace std;
int main()
{
int a = 5000000, b = 10000; //-2147483648~2147483647
short int c{a};
short int d{b};
cout << c << endl;
cout << d << endl;
return 0;
}
默认都为0
有效位降低是不允许的!
也就是缩窄
double放在long中不允许
数组替代品 vector
字符串
一种是,C语言风格,把字符串存在数组里
第二种,基于string类库的方法
字符串要以\0
结尾
第一个就不是string
第一个是字符数组
他会自动加上\0 编译器加进来的
单引号是字符,双引号是字符串
双引号里面是两个,外加一个\0
字符串常量存的是地址
在数组中操作字符串
strlen 字符串长度
sizeof() 占用内存空间
15字节
strlen字符串长度忽略\0
第二次输入就没了
我们加了个空格
cin使用空白字符(空格,回车,制表符)
确定字符串
他认为当前结束了
dreeb会存到缓冲区
都会放在输入缓冲区
直接去缓冲区读取,
getline()
每一次读取一行字符串输入
cin.getline()
设置20 最多会读取19个字符
#include<iostream>
# include<cmath>
#include<climits>
# include<cstring>
using namespace std;
int main() {
const int Size = 20;
char name[Size];
char dessert[Size];
cout << "11" << endl;
cin.getline(name, Size);
cout << "22" << endl;
cin.getline(dessert, Size);
cout << "delicious" << dessert << endl;
return 0;
}
get()
和getline一样,都是对行的接收
get会丢弃换行符,遇到换行符结束
输入后直接会跳两次
空字符,没输入
中间接受一个回车
函数重载
参数列表不同参数名字相同
string 类简介
可以通过数组的类型来操作string,下标之类的都可以
赋值,拼接,附加
可以把string对象,赋值给另一个string对象
附加
#include<iostream>
# include<string>
using namespace std;
int main() {
char charr1[20];
char charr2[20] = "jaguar";
string str1;
string str2 = "panther";
cout << "Enter a kind of feline"<< endl;
cin >> charr1;
cout << "Enter another kind of feline : ";
cin >> str1;
cout << "Here are some felines:\n";
cout << charr1 << " " << charr2 << " "<< str1 << " " << str2 << endl;
return 0;
}
strcp(charr1,charr2)
复制
sstr1+=""
strcat(charr,“juice”);
z字符串连接
string类I/O
如何用getline读取一大串,存在string中
strlen 查看一下,发现和20不一样,
因为我们没有进行输入值,内存中随机的
我们查看str.size()
cin.getline
和
getline
结构体设定
允许声明结构体省略struct
填充的时候需要逗号
外部声明,在所有中都可见
perk在main函数内可见
同一种结构体类型就能直接赋值
结构体和类型直接声明
同时赋值也可以
不推荐这么干
结构体的位字段
标志着你有多少位,多少bit
位字段是低级编程
4.5 共用体
union是一个数据格式
联合体中,三选一,同一时间,只能使用一个
和结构体很相似
共用体长度为最大长度
#include<iostream>
using namespace std;
union one2all {
char ch;
int n;
};
int main() {
one2all num;
cout << "sizeof(num)= " << sizeof(num) << endl;
return 0;
}
比如你存一个 A 他int 输出 65 他字符串输出A
同一个内存空间
结构体放结构体,结构体放联合体都可以
可以用联合体查看计算机是大端模式还是小端模式
4.6 枚举
C++ 的 enum 工具提供了创建符号常量的方法
也相当于struct这种
这样的话,red,orange,等等,都变成了常量
里面的每个值都是整型,从零开始
枚举类型声明这种变量,
spectrum band
同时,只能将定义枚举的枚举量赋值给枚举的变量
只能给0-7或者是red等
枚举类型,只能赋值,没有算数运算
可以转换为int 比如转成0 1 之类的
低转高
枚举类型,为了定义常量,而不是创建新的常量
设置枚举量的值
比如认识整数哟
他有上限和下限,这里赋值就可以
他的限制必须是最大的2的幂次 (2的三次 =8 二的四次-1 也就是15)
4.7 指针和自由存储空间
存储到何处?
值为多少,
存储的信息是什么类型
求出他值得地址,
加一个取地址符号
如何声明指针
指针里面放地址
#include<iostream>
using namespace std;
int main() {
int updates = 6;
int *p_updates;
p_updates = &updates;
cout << "value : updates = " << updates << endl;
cout << "p_updates = " << p_updates << endl;
return 0;
}
4.7.2 指针的危险
他地址并不明确,给地址里面送值会有bug
4.7.4 使用new来分配内存
指针是访问内存的别名
new运算符分配内存,比malloc好多了
new会返回内存块的地址
int *pn = new int
;
typeName * pointer_name = new typeName
#include<iostream>
using namespace std;
int main() {
int nights = 1001;
int *pt = new int;
*pt = 1001;
cout << "nights value = " << nights << "address " << &nights << endl;
cout << "int value = " << *pt << "address value = " << pt << endl;
double * pd = new double;
*pd = 10000001.0;
cout << "double value = " << *pd << "address " << pd << endl;
return 0;
}
使用delete释放内存
只会删除内存空间,释放掉,不会删除ps指针,
new 和 delete要成对使用,
delete后不要delete,结果不可预知
delete 不呢个释放声明变量所获得的内存
没new,就不能delete
小数据,直接定义就行,大量数据,还是new方便
静态创建数组,浪费,new的时候,不需要就可以不用开创空间
动态联编
使用new创建动态数组
int * psome = new int [10];
释放数组:
delete [] psome;
如果不带方括号
释放的只是第一个元素
指针是变量,数组值是 常量
数组不能增加/运算之类,
指针,数组,指针算术
数组的动态联编和静态联编
使用new[]
不用不分配
指针和字符串
相当于打印了rose第一个字母r,一次性取出所有字符串,rose 直到找到\0
strncpy() 拷贝多少个
防止溢出
new char 数组
动态开辟空间
new动态创建结构体
优于编译时候
结构体类型指针
这样也可以实现
接收动态字符串开辟空间函数
类型组合
数组的替代品
模板类vector
用的是圆括号了这儿
vector<typeName> vt(n_elem);
vector代价,效率比较低
功能强大
模板类array
array长度是固定数组
array<int ,5> ai;
v
vector 是存储在堆中,肯定和其他存储的不一样】
#include<iostream>
#include<vector>
#include<array>
using namespace std;
int main() {
int nights = 1001;
double a1[4] = { 1.2,2.4,3.6,4.8 };
vector<double> a2(4);
a2[0] = 1.0 / 3.0;
a2[1] = 1.0 / 5.0;
a2[2] = 1.0 / 7.0;
a2[3] = 1.0 / 9.0;
array<double, 4> a3 = { 3.14,2.72,1.62,1.41 };
array<double, 4> a4;
return 0;
}
使用成员函数,可以使用at来进行检测下标越界
循环
这样没加括号,他会等号分开两边
都不认识
输出 0 1 之类的
阶乘的输出
第八章 函数探幽
C++ 内联函数
为了提高程序运行速度
运行速度快
常规函数,很废时间
花费精力,入栈出栈
代码执行短的话,方便内联
square就是内联函数
#include<iostream>
using namespace std;
inline double square(double x) { return x * x; };
int main() {
double a, b;
double c = 13.0;
a = square(5.0);
b = square(4.5 + 7.5);
cout << "a = " << a << "b = " << endl;
cout << "c = " << c << endl;
cout << "Now c = " << square(c++) << endl;
return 0;
}
8.2 引用变量
引用就是定义变量的别名
创建引用变量
rats 和rodents 可以互换
引用和指针还是有区别的
将引用用作函数参数
形参实参一回事儿了
形参操纵实参,
脱离C语言
名字一样,参数不同,也可以哟~
8.5函数模板
交换两个数的值
怎么写呢?
函数重载,也可以使用函数模板
c++函数模板功能可以自动完成这一过程
template <typename anytype>
和class差不多
类型名称任意选
为了方便,一般都写T ,图省事
可以接收任意类型~
两次替换,可以模板函数,也可以函数重载
#include<iostream>
using namespace std;
template<typename T>
void Swap(T &a, T &b);
int main() {
int i = 10;
int j = 20;
cout << "i,j = " << i << "," << j << "." << endl;
Swap(i, j);
cout << "after swap ,now i,j = " << i << "," << j << endl;
double x = 24.5;
double y = 81.7;
cout << "i,j = " << x << "," << y << "." << endl;
Swap(x, y);
cout << "after swap ,now i,j = " << x << "," << y<< endl;
return 0;
}
template <typename T>
void Swap(T &a,T &b) {
T temp;
temp = a;
a = b;
b = temp;
}
编写是一个,但是编译器会最终编译生成两个
8.5.1重载的模板
如果说我们想交换数组,必须要重载,不重载很明显就不可以
输出没有任何问题
#include<iostream>
using namespace std;
template<typename T>
void Swap(T &a, T &b);
const int LIM = 8;
void show(int arr[], int n);
int main() {
int i = 10;
int j = 20;
cout << "i,j = " << i << "," << j << "." << endl;
Swap(i, j);
cout << "after swap ,now i,j = " << i << "," << j << endl;
int d1[LIM] = { 0,7,0,4,1,7,7,6 };
int d2[LIM] = { 0,7,2,0,1,9,6,9 };
cout << "origianl arrays" << endl;
show(d1, LIM);
show(d2, LIM);
return 0;
}
template <typename T>
void Swap(T &a,T &b) {
T temp;
temp = a;
a = b;
b = temp;
}
void show(int arr[], int n) {
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
我们来写模板
#include<iostream>
using namespace std;
template<typename T>
void Swap(T &a, T &b);
template<typename T>
void Swap(T a[], T b[], int n);
const int LIM = 8;
void show(int arr[], int n);
int main() {
int d1[LIM] = { 0,7,0,4,1,7,7,6 };
int d2[LIM] = { 0,7,2,0,1,9,6,9 };
cout << "origianl arrays" << endl;
show(d1, LIM);
show(d2, LIM);
Swap(d1, d2, LIM);
cout << "Swapped arrays = " << endl;
show(d1,LIM);
show(d2, LIM);
return 0;
}
template <typename T>
void Swap(T &a,T &b) {
T temp;
temp = a;
a = b;
b = temp;
}
template<typename T>
void Swap(T a[], T b[], int n) {
T temp;
for (int i = 0; i < n; i++) {
temp = a[i];
a[i] = b[i];
b[i] = temp;
}
}
void show(int arr[], int n) {
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
8.5.2 模板的局限性
交换结构体,直接把所有东西都交换了
我只想交换钱,
重载,参数类型,数量需要不同
8.5.3 显式具体化
template <> void Swap(job &j1,job &j2)
告诉编译器。如果传过来的是job类型,就不能去用其他的模板
成功替换
#include<iostream>
using namespace std;
template<typename T>
void Swap(T &a, T &b);
template<typename T>
void Swap(T a[], T b[], int n);
const int LIM = 8;
void show(int arr[], int n);
struct job
{
char name[40];
double salary;
int floor;
};
template <> void Swap<job>(job &j1, job &j2);
void show(job &j);
int main() {
int d1[LIM] = { 0,7,0,4,1,7,7,6 };
int d2[LIM] = { 0,7,2,0,1,9,6,9 };
cout << "origianl arrays" << endl;
show(d1, LIM);
show(d2, LIM);
Swap(d1, d2, LIM);
cout << "Swapped arrays = " << endl;
show(d1,LIM);
show(d2, LIM);
job Rick = { "Rick",100,10 };
job Jack = { "Jack",1100,11 };
show(Rick);
show(Jack);
Swap(Rick, Jack);
show(Rick);
show(Jack);
return 0;
}
template <typename T>
void Swap(T &a,T &b) {
T temp;
temp = a;
a = b;
b = temp;
}
template<typename T>
void Swap(T a[], T b[], int n) {
T temp;
for (int i = 0; i < n; i++) {
temp = a[i];
a[i] = b[i];
b[i] = temp;
}
}
void show(int arr[], int n) {
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
void show(job &j) {
cout << j.name << ":" << j.salary << "onfloor" << j.floor << endl;
}
template <> void Swap<job>(job &j1, job &j2) {
double t1;
int t2;
t1 = j1.salary;
j1.salary = j2.salary;
j2.salary = t1;
t2 = j1.floor;
j1.floor = j2.floor;
j2.floor = t2;
}
优先显示具体化的函数
8.5.4 实例化和具体化
自己选择 合适的函数调用
我们定义一个模板函数和一个非模板函数
非模板函数优先
#include<iostream>
using namespace std;
template<class T>
T lesser(T a, T b) {
return a < b ? a : b;
}
int lesser(int a, int b) {
a = a < 0 ? -a : a;
b = b < 0 ? -b : b;
return a < b ? a : b;
}
int main(void) {
int m = 20;
int n = -30;
double x = 15.5;
double y = 25.9;
cout << lesser(m, n) << endl;
return 0;
}
这样,优先使用模板函数
#include<iostream>
using namespace std;
template<class T>
T lesser(T a, T b) {
return a < b ? a : b;
}
int lesser(int a, int b) {
a = a < 0 ? -a : a;
b = b < 0 ? -b : b;
return a < b ? a : b;
}
int main(void) {
int m = 20;
int n = -30;
double x = 15.5;
double y = 25.9;
cout << lesser(m, n) << endl;
cout << lesser<>(m, n) << endl;
return 0;
}
告诉模板函数,参数强转为int
单独编译
工程可能会包含很多源代码和头文件
除了内联函数,其他定义不放头文件
可以写.c .cpp 专门来调用其他
上面那些东西都放头文件里面
一个 功能一个cpp比较香
把两个拆开,然后编译,然后链接
保证了项目只会定义一次,
if not define 如果没有定义过,然后才会去定义头文件,
有if 必须要有endif
双引号,代表去你当前目录去获取头文件
函数调用
file1.cpp
# include<iostream>
#include "coordin.h"
using namespace std;
int main(void) {
rect rplace;
polar pplace;
cout << "Enter the x and y values :";
while (cin >> rplace.x >> rplace.y) {
pplace = rect_to_polar(rplace);
show_polar(pplace);
cout << "Next two number (q to quit):";
}
return 0;
}
函数原型声明 .h
#pragma once
#pragma once
#ifndef __COORDIN_H__
#define __COORDIN_H__
struct polar
{
double distance;
double angle;
};
struct rect {
double x;
double y;
};
polar rect_to_polar(rect xypos);
void show_polar(polar dapos);
#endif // !__COORDIN_H__
函数定义
file2.cpp
#include<iostream>
#include<cmath>
#include "coordin.h"
using namespace std;
polar rect_to_polar(rect xypos) {
polar answer;
answer.distance = sqrt(xypos.x * xypos.x + xypos.y * xypos.y);
answer.angle = atan2(xypos.y, xypos.x);
return answer;
}
void show_polar(polar dapos) {
const double Rad_to_deg = 57.29577951;
cout << "distance = " << dapos.distance << endl;
cout << "angle = " << dapos.angle * Rad_to_deg << " degree " << endl;
}
存储秩序性,作用域和链接性
形参,实参,以及参数的区域,c学过了
使用C++ 11 中的auto
register auto
extern
声明函数,说明这个参数是外来的,这里只是想用到
作用域解析运算符
::
加上以后相当于调用全局变量
这里的::warming ,表示使用的全局版本
support.cpp
#include "support.h"
using namespace std;
void update(double dt) {
warming += dt;
cout << "Update" << warming << endl;
}
void local(void) {
}
external.cpp
# include<iostream>
# include "support.h"
using namespace std;
double warming = 0.3;
int main(void) {
cout << "Global warming is " << warming << "degrees." << endl;
update(0.1);
cout << "Global warming is " << warming << "degrees." << endl;
return 0;
}
support.h
#pragma once
#ifndef __SUPPORT_H__
#define __SUPPORT_H__
#include<iostream>
extern double warming;
void update(double dt);
void local(void);
#endif
静态持续性,内部链接性
内部只能内部文件用,
就近原则,差不多~
file1.cpp
file2.cpp
无链接性的局部变量
其他函数,文件,看不到你
cin.get() 获取内容
total只再第一次调用。count会掉一次初始化位0
total 值之后就不变了
说明符和限定符
auto 自动匹配 变量类型
register 分配内存分配到寄存器
CV限定符
volatile和mutable
固件用的比较多
const
链接性为内部的,不会影响到其他文件
函数和链接性
C++ 不允许一个函数中,定义另一个函数,所有的函数存储持续性为静态
extern 函数指出另一个文件中定义,是可选的,默认不写
函数static 定义,只能在一个文件中使用
语言的链接性
C语言一个名称一个函数
C++ 中同一个名称可能多个函数
编译器可能会改他的名字
存储方案和动态分配
new开辟,delete释放
使用new进行初始化
开辟内存空间,初值为6
定位new运算符
可以指定,存放的位置
使用new
处理特定位置i访问的硬件或者是创建对象
指定在那个内存空间中,
指定在buffer1里面
new定位运算符,需要new头文件
c++,我们想要输出字符串的地址,buffer,这样肯定式字符串,我们要强制转换,让他知道我们出地址
很明现,这两个地址不一样
我们发现,pd2和buffer一样的
delete的时候
delete 不能用于定位的new运算符
delete 删除的是动态内存,动态释放内存,new也是
9.3 名称空间
不同厂家类库,可能会冲突~
9.3.2 新的名称空间特性
我们可以使用任意一个名称,用的时候,写具体就可以
名称空间包含名称空间也可以,默认外部,但是不能在代码块中
新的名称,随便加
当然,需要作用域解析运算符
指名道姓
using 声明和using 编译指令
放到了局部声明区域
编译指令
如果使用fetch,优先局部变量,不会进行冲突
名称空间的套用
这样using的编译指令
未命名的名称空间
从声明开始,到结束
第十章 类和对象
通过public方法,调用private的隐私数据
头文件只做类的声明,不会把他具体写出来
访问控制
只有通过public能改private
控制对成员的访问,公有还是私有
没private,数据默认私有,
stock00.h 头文件
#pragma once
#ifndef __STOCK00__H__
#define __ STOCK00__H__
#include<string>
class Stock
{
private:
std::string company;
long shares;
double share_val;
double total_val;
void set_total() { total_val = shares * share_val };
public:
void acquire(const std::string &co,long n,double pr);//哪一个公司的股票
void buy(long num, double price);
void sell(long num, double price);
void update(double price);
void show();
};
#endif
10.2.3 实现类成员函数
用 :: 标识类
我们可以跟另一个也可以定义同样的函数
类内,不需要指定
内联方法
定义位于类声明中的函数都将自动成为内联函数
函数声明时候,就定义了,这个就自动成为了内联函数
如果有inline 也会是内联函数
放在外面实现
类的定义
stock00.cpp
#include<iostream>
#include "stock00.h"
void Stock::acquire(const std::string &co,long n,double pr) {
company = co;
if (n < 0) {
std::cout << "Number of share can't be negative;" << company << std::endl;
}
else
shares = n;
set_total();
}
void Stock::buy(long num, double price) {
if (num < 0) {
std::cout << "number of shares can't be negative,Transaction is aborted" << std::endl;
}
else {
shares += num;
share_val = price;
set_total();
}
}
void Stock::sell(long num, double price) {
using std::cout;
if (num) {
std::cout << "number of shares can't be negative " << std::endl;
}
else if (num > shares) {
cout << "you can't sell more than you have " << std::endl;
}
else {
shares -= num;
share_val = price;
set_total();
}
}
void Stock::update(double price) {
share_val = price;
set_total();
}
void Stock::show() {
std::cout << "Company: " << company << std::endl;
std::cout << "Shares: " << shares << std::endl;
std::cout << "share price : " << share_val << std::endl;
std::cout << "TOtal worth:" << total_val << std::endl;
}
10.2.4 使用类
#include<iostream>
#include"stock00.h"
int main(void) {
Stock fluffy_the_cat;
fluffy_the_cat.acquire("wuwu",20,12.5);//第一次获取一个股票
fluffy_the_cat.show();
fluffy_the_cat.buy(15, 18.125);//再买多少zhi,meizhi多少钱
fluffy_the_cat.show();
fluffy_the_cat.sell(400, 20.00);//尝试卖400份,查看报错
fluffy_the_cat.show();
return 0;
}
卖多了,提示,不能卖
类的构造和析构函数
不能将参数当作构造函数的参数
避免混乱,我们在数据前面加前缀m_
构造函数没有返回值~~
stock10.cpp
#include<iostream>
#include"stock00.h"
Stock::Stock(const std::string &co, long n, double pr) {
company = co;
if (n < 0) {
std::cout << "Number of share can't be negative;" << company << std::endl;
shares = 0;
}
else
shares = n;
share_val = pr;
set_total();
}
C++ 提供了两种方法来构造函数,第一种是显式的 调用构造函数
使用构造函数
如果使用默认参数,这里在声明中直接填入值(默认值)
另一种方式是函数重载,来定义另一个构造函数,一个没有参数的构造参数,
上面两种只能采用其一。否则会冲突
usestock2.cpp
#include<iostream>
#include "stock00.h"
int main(void) {
/*
Stock stock1("Nanosmart", 12, 20.0);
stock1.show();
Stock stock2 = Stock("Boffo objects", 2, 2.0);
stock2.show();
*/
Stock stock1;
stock1.show();
}
stock.cpp
#include<iostream>
#include"stock00.h"
/*
Stock::Stock(const std::string &co, long n, double pr) {
company = co;
if (n < 0) {
std::cout << "Number of share can't be negative;" << company << std::endl;
shares = 0;
}
else
shares = n;
share_val = pr;
set_total();
}*/
Stock::Stock() {
company = "no name";
shares = 0;
share_val = 0.0;
total_val = 0.0;
}
stock00.h
#pragma once
#ifndef __STOCK00__H__
#define __ STOCK00__H__
#include<string>
class Stock
{
private:
std::string company;
long shares;
double share_val;
double total_val;
void set_total() { total_val = shares * share_val; };
public:
Stock();
//Stock(const std::string &co, long n, double pr);
void acquire(const std::string &co,long n,double pr);//哪一个公司的股票
void buy(long num, double price);
void sell(long num, double price);
void update(double price);
void show();
};
#endif
stock00.cpp
#include<iostream>
#include "stock00.h"
void Stock::acquire(const std::string &co,long n,double pr) {
company = co;
if (n < 0) {
std::cout << "Number of share can't be negative;" << company << std::endl;
shares = 0;
}
else
shares = n;
share_val = pr;
set_total();
}
void Stock::buy(long num, double price) {
if (num < 0) {
std::cout << "number of shares can't be negative,Transaction is aborted" << std::endl;
}
else {
shares += num;
share_val = price;
set_total();
}
}
void Stock::sell(long num, double price) {
using std::cout;
if (num) {
std::cout << "number of shares can't be negative " << std::endl;
}
else if (num > shares) {
cout << "you can't sell more than you have " << std::endl;
}
else {
shares -= num;
share_val = price;
set_total();
}
}
void Stock::update(double price) {
share_val = price;
set_total();
}
void Stock::show() {
std::cout << "Company: " << company << std::endl;
std::cout << "Shares: " << shares << std::endl;
std::cout << "share price : " << share_val << std::endl;
std::cout << "TOtal worth:" << total_val << std::endl;
}
传参了,就一定不是默认的构造函数
第三个,默认的构造函数
10.3.4 析构函数
对象使用完毕后,会自动调用析构函数,
如果在构造函数中new来分配内存,析构函数将调用delete释放
析构函数也没有返回值和类型
析构函数没有参数
~Stock();
同时,因为上一个没new,所以,析构函数为空
10.4 this指针
如果我们需要比较,两个类的时候,
我们要比较两个类对象,
指向用来调用成员函数的对象,this表示正在访问的对象,
tips
*this 这样表示了整个调用对象
这里的return就是*this
this指针指向调用成员的对象
10.5 对象数组
构造函数初始化数组