C++ 学习笔记
#include <iostream>
#include <string> //string 类
#include <string.h> //也是字符串
#include <stdlib.h>
#include <vector>
#include <array>
using namespace std;
inline double sq(double x )
{
return x*x;
}
int main ()
{
double x;
std::cout << "输入一个数:" << std::endl;
cin>>x;
std::cout << "这个数字的平方是" << sq(x)<< std::endl;
return 0;
}
/* C++ 允许程序在任何地方声明新的变量 还允许在创建变量时对他进行赋值(这就是初始化)
coutfill('%')和setfill('%')在从设置行向后,才能填充设置的字符
long是代表长双精度型 long long
类是用户定义的一种数据类型,描述其能够表达什么数据信息(也就是属性);还有一个就是可对数据执行那些操作(方法)定义类:数据格式+使用方法 对象是根据数据格式规范创建的实体
C++ 提供两种发送消息的方式,一种是使用类方法,本质上就是使用函数调用;另一种就是重新定义运算符。
C++ 的函数分为两种,有返回值的和没有返回值的。
有返回值的函数 调用函数 被调用函数 返回函数
C++程序应当为程序中使用的每个函数提供原型 就是函数的整个调用使用的整套格式(这就是原型) 不是函数
C++库函数存储在库文件中,编译器编译程序时,必须在库文件中搜索您使用的函数。
在设计类的时候,需要自己编写函数。
在进行子函数的调用时,要将写好的子函数在头文件或者主函数内部进行一个声明(也就是函数头),不然函数会报错 void 说明函数不会有返回值 如果这么声明说明不需要return.
main 函数的 return 0; 返回语句只适用于main函数,不适用与其他函数 可以看成是操作系统调用main函数,所以main函数的返回值是返回给操作系统
关键字: int void return double main不是关键字 他不是语言组成的一部分 是一个必不可少的函数名称
用户定义的有返回值的函数 就是将前面和的 void换成其他就可以了。
从main执行 函数头 函数体
可以使用#define 和const 指定常量 #define N 100(这个在头文件下面) const int N=100;(任意位置)
auto 自动类型推断
判断语句 if 和 else 后面应该格子分开包裹大括号 switch 就是多选择
函数 形参不声明 子函数可以写在主函数上下都行 其余没啥变化
匿名函数 lambda函数/表达式 只是用一次的函数对象类 直接在其使用的地方定义 还没学会
=是不允许 & 允许 表示{}中用到的,定义在大括号外面的变量在{}中是否被允许改变 这个表示定义在{}外面的变量在大括号中不允许被改变
布尔型就是逻辑型
递归 就是调用自身 去实现某些功能 写一个子函数 这个子函数里面有调用其本身的字眼就行 然后再在主函数 进行调用。
内联函数 通常与类一起使用 在编译时 编译器会把该函数的代码副本放在每个调用该函数的地方。对内联函数的任何修改,都需要重新编译函数所有的客户端,因为编译器需要重新更换所有的代码,否则将会继续使用旧的函数 形式: 子函数函数名前面加上 inline //前面加个inline 相当于将整个子函数在调用的位置上重新写了一遍
传值和传址的理解 传值 就是穿进去的参数跑进去跑出来不会变 但是传值跑进去的跑出来就变了
函数重载 函数名相同 但是形参的格式不同 同一个函数名还是要在主函数前面声明一下,使用的时候还是根据其功能使用 目的是为了方便使用函数名
静态局部变量 静态全局变量 拒不存储位置不变 编译时才会赋值 都是 static 还有静态函数也是这种表述 这样表述的函数只能被本文所使用
全局变量 可被其他文件调用的函数 都使用 extern 一般省略 extern 直接看成可以被其他文件进行调用 调用是时使用 还是extern 或者 #include
数组 这个都能明白 字符串数组 一个char 宽度为一个字节 字符串后面还跟着一个 \0 是为了截断 换行 数组之间不能直接赋值 要挨个赋值 也就是要写个循环赋值 */
//结构体 结构体数组
/* struct student //结构的使用 这是全局结构声明 也可以局部声明
{
char name[20]; //类型1 字符串
float shengao; //类型2 浮点数
double tizhong; //类型3 双精度浮点数
};
// 程序的主函数
int main(int argc, char const *argv[])
{
struct student first1 = //struct 可要可不要 等号 = 可要可不要 可函数内部可函数外部 但是尽量变量放在内部声明不出去
{
"wangjie", 1.87,93.5
};
struct student first2 =
{
"lihui", 1.87,93.5
};
cout << "第一个学生的属性:" << "\n"<< " 姓名:" << first1.name << " 身高:" << first1.shengao << " 体重: " << first1.tizhong <<endl;
return 0;
} */
/* 结构体 数组之间的赋值
struct student
{
char name[20];
float zhongliang;
double shengao;
}stu1;
int main(int argc, char const *argv[])
{
struct student stu[2] =
{
{"wangjie",92.5,1.87},
{"lihui",92.5,1.87}
};
int i;
std::cout << "学生1的名字:" << stu[0].name << " 学生1的重量:" << stu[0].zhongliang << " 学生1的身高: " << stu[0].shengao << std::endl;
struct student choice[2];
for ( i = 0; i < 2; i++)
{
choice[i] = stu[i];
std::cout << i << " "<< "choice:" << choice[i].name << choice[i].zhongliang << choice[i].shengao << std::endl;
}
return 0;
} */
// 指针与C++基本原理:面向对象编程与传统面向过程编程的区别在于:OOP强调的是在运行阶段(而不是编译阶段)进行决策,运行阶段指的是程序在运行时,编译阶段指的是编译器将程序组合起来时。 运行阶段决策提供了灵活性,可以根据当时的情况进行调整。OOP通过将程序需要的内存在运行时再去告诉计算机,这样就不会浪费内存。 OOP在运行阶段确定数组长度,C++允许在程序运行时创建数组(使用关键字new请求正确数量的内存以及使用指针来跟组新分配的内存的位置)
// 处理存储数据时恰好相反 将变量的物理地址(这就是指针)视为指定的量,而将其值视为派生量,指针可以看做是存储变量值的地址,所以指针名表示的是地址。 *运算符被成为间接值或者叫作解除引用运算符 使用这个就会表达出来这个地址位置存储的变量的值 & 叫取址符 使用这个符号表达的意思就是取出这个物理量的存储位置(物理地址)
// int main(int argc, char const *argv[])
// {
// int wanshang = 1001; //整型
// int *pt =new int; //将整型的地址赋给一个指针,只能通过指针进行访问 为这种类型的数据对象获取指定分配内存
// *pt = 1001;
// std::cout << "(这是个整型)wanshang的物理值 " << wanshang <<std::endl;
// std::cout << "wanshang的内存地址 " << &wanshang<< std::endl;
// std::cout << "int 的值 " << *pt << ";int的位置 "<<pt<< std::endl;
// return 0;
// }
// 要创建指针变量 每一个前面都需要加*
// 指针:用来分配存储地址的内存,而不是分配存储指针所指向数据的内存
// 一定要在对指针应用解除引用运算符*之前,将指针初始化为一个确定的、适当的地址。(金科玉律)
// 指针管理运行阶段的内存空间分配
/* int main(int argc, char const *argv[])
{
int a = 10,c=30;
const int b =20;
const int i = 20;
int k = 40;
const int * p ;
p = &i; //只可指向i 不可修改i
cout <<*p <<" "<< i<< endl;
p= &k;
cout << *p << k;
int p;
p=*p1;
*p1=*p2;
*p2=p; //指针变量之间的物理数值的调换
double wa[3] = {10000.0,20000.0,30000.0};
short st[3] = {3,2,1};
// 使用指针
double * pw = wa;
short *ps= &st[0]; // 取的是数组第一个下标的物理地址 所以是一个指针常量
cout <<" pw " << pw <<" * pw = "<<*pw <<endl;//取值 wa是一个数组 取的是第几个数值 指向的是wa这个数组的地址
pw+=1;
std::cout << "给指针变量加1 \n" << std::endl; //相当于给数组的下标往后走了一位 所以是20000
cout <<" pw " << pw <<" * pw = "<<*pw <<endl;
cout <<" ps " << ps <<" * ps = "<<*ps <<endl; //取的是数组第一个 3 的物理地址
ps+=1;
std::cout << "给ps的指针变量加1" <<" ps " << ps <<" * ps = "<<*ps<< std::endl;
std::cout << "st[0]" <<st[0]<<"\n"<< "st[1]" <<st[1]<< std::endl;
std::cout << "*st ="<< *st <<"\n"<<"*(st+1) = " <<*(st+1) << std::endl; //指针数组的指向作用
return 0;
} */
//指向常量的指针变量 const int i =20 只可读取 不可修改
// 整型的常量和指针常量 都是不可修改的 字符型的指针常量 指针指向的地方不能修改 但是代表的字符常量可以修改 指针指向的变量是可以修改的
//指针在参数传递中有三个作用(也就是指针作为函数进行参数传递的三个作用):
// 1 形参实参指向共同的内存空间,达到参数双向传递的目的
// 2 减少函数调用时数据传递的开销
// 3 传递实际参数的首个地址 (弄了半天是作用最小的那个)
//数组名就代表这数组的首地址 也就是数组中下标序号为0 的元素的地址
/* int main(int argc, char const *argv[])
{
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;
a4 =a3;
std::cout << "a1[2] " <<a1[2]<< std::endl;
std::cout << "a2[2] " <<a2[2]<< std::endl;
std::cout << "a3[2] " <<a3[2]<< std::endl;
std::cout << "a3[2] " <<a4[2]<< std::endl;
}*/
/* C++ 分配内存的方法: 自动存储、静态存储、动态存储、自由存储空间或堆
模板类 vector 是一种动态数组,是使用new创建动态数组的替代品
1 必须包含头文件 vector ;2 必须包含在std 名空间中 就是直接声明使用名空间就好了;3 模板使用不同的语法来指出他的数据类型 4 vector 类使用不同的语法来指定元素数
模板类:
vector<typeName> vt(n_elem);
array<typeName,n_elem> arr; 这个n_elem 不能是变量
引用 不论是引用变量、指针变量、函数 都是在前面加 & 符号,函数传址是在前面加上 * 符号 引用变量在内存中没有地址,和被引用的使用同一个内存地址
作为函数引用效果和传递指针的效果一样
常引用的作用有两个,一是让变量所指向的内存空间只读,二是能够指向常量 void getTeacher(const teacher &t) 也就是在子函数的形参中 不仅写出const 再在需要引用的变量前面加上引用地址符 &
常引用 const int &a=b 相当于 const int * const a=b 不仅仅是a这个地址不可修改,而且其指向的内存空间也不可修改
*/
/* 类 还是 结构的变化体 声明的时候注意声明的对象首字母要大写 大括号中包含 private protected public 这三种不同权限的数据成员或者叫作成员函数 这只是三种不同的权限 在定义成员函数的时候 需要加上 :: 这个符号用以特指 返回值类型 类的名称::成员函数名(引入的参数)。
一般做法:将类的定义卸载一个头文件中(.h文件),将成员函数的定义写在一个程序文件中(.cpp)。这样子相当于把类的定义看成了类的外部接口,而把成员函数看成是类的内部实现。
.cpp 文件先要包含其他头文件 还要包含你定义的这个头文件,这个头文件才能发挥作用。
对象:类的实例 类是一种抽象的数据类型,对象是实际的概念 对象是属于该类的一个变量 每个对象都具有该类的一套数据成员,所有成员函数的所有对象共有的。
类中的私有成员只能通过其成员函数进行访问 ,也就是说 private里面和public里面 有一个交界 这个交界就是成员函数 私有其实就是为了限制权限 访问私有必须通过向对象发送同类型的消息 注意同类型
纯虚函数:就是直接定义虚函数为0 virtual 函数原型 =o;
抽象类:就是包含纯虚函数的类,不能有对象,因为它的数据类型直接为0,就没有对象,可以声明其指针变量和引用变量 可以有多个纯虚函数、非纯虚函数 类继承越复杂 上层的类抽象程度越高,所以抽象类一般居于类继承结构的较上层。
友元函数 就是在定义类的成员函数时 在这个成员函数前面加个 friend 这样子 这个
*/
/* #include <iostream>
#include <string> //string 类
#include <string.h> //也是字符串
#include <stdlib.h>
#include <vector>
#include <array>
using namespace std;
class Complex
{
private:
double r;
double i;
public:
Complex(double x=0.0, double y=0.0)
{
r=x;
i=y;
}
Complex operator +(const Complex &c);
void print();
};
Complex Complex::operator+(const Complex &c)
{
Complex t;
t.r=r+c.r;
t.i=i+c.i;
return t;
}
void Complex::print()
{
std::cout <<'('<< r <<','<< i <<')'<< std::endl;
}
int main()
{
Complex a(3.0,4.0),b(10.5,20.5),c;
c=a+b;
c.print();
return 0;
} */
/* // 类模板 这是将函数成员定义体 放在 类模板 成员函数定义体 外部 定义的实例。
template <class T, int N > class ABC //定义模板类
{
private:
T array[N];
public:
void set(int x)
{
int i;
for ( i = 0; i < N; i++)
{
array[i]=x+i;
// std::cout << i << std::endl;
std::cout << "array["<< i<<"]="<< array[i] << std::endl;
}
}
void get()
{
std::cout << "数组元素为"<<N << std::endl;
std::cout << "array["<< N-1<<"]="<< array[N-1] << std::endl;
}
};
int main(int argc, char const *argv[])
{
ABC<int,50>abc1;
abc1.set(0);
abc1.get();
ABC<int,100>abc2;
abc2.set(10);
abc2.get();
return 0;
} */
/* // 类模板 这是将函数成员定义体 放在 类模板 成员函数定义体 内部 定义的实例。
template <class T, int N > class ABC //定义模板类
{
private:
T array[N];
public:
void set(int x);
void get();
};
//将成员函数写在外面
template <class T, int N >
void ABC<T,N>::set(int x)
{
int i;
for ( i = 0; i < N; i++)
{
array[i]=x+i;
// std::cout << i << std::endl;
std::cout << "array["<< i<<"]="<< array[i] << std::endl;
}
}
template <class T, int N >
void ABC<T,N>::get()
{
std::cout << "数组元素为"<<N << std::endl;
std::cout << "array["<< N-1<<"]="<< array[N-1] << std::endl;
}
int main(int argc, char const *argv[])
{
ABC<int,50>abc1;
abc1.set(0);
abc1.get();
ABC<int,100>abc2;
abc2.set(10);
abc2.get();
return 0;
} */
/* template <class T>
T maxx(T a, T b)
{
a>b?a:b;
/* if (a>b)
{
return a;
}
else
{
return b;
} */
/* }
int main()
{
int i1=20,i2=10;
double d1=-5.43,d2=50.23;
char c1='A',c2='a';
std::cout << "相比之下较大的为:" << maxx(i1,i2)<<std::endl;
std::cout << "相比之下较大的为:" << maxx(d1,d2)<< std::endl;
std::cout << "相比之下较大的为:" << maxx(c1,c2)<< std::endl;
return 0;
} */