析构函数
class pren{
public:
//构造函数
//没有返回值 不用写void
//函数名和类名相同
//构造函数可有参数可以重载
//创建对象的时候就会自动调用且只调用一次
pren(){
cout << "123" << endl;
}
//析构函数
//没有返回值 不用写void
//函数名和类名相同,要在函数名前添加~符号
//构造函数不可有参数不可以重载
//对象销毁之前就会自动调用且只调用一次
~pren(){
cout << "456" << endl;
}
};
//如果不识闲,编译器就会实现空的构造析构函数
void t1(){
pren p1;//局部变量在栈上,t1执行完就会释放对象
}
int main(){
//变量在主函数中,构造函数在程序结束前不会释放所以析构不会在程序运行时执行在结束后执行
pren p;
//t1();
system("pause");
return 0;
}
构造函数
构造函数
没有返回值 不用写void
函数名和类名相同
构造函数可有参数可以重载
创建对象的时候就会自动调用且只调用一次
class pren{
public:
//构造函数
//没有返回值 不用写void
//函数名和类名相同
//构造函数可有参数可以重载
//创建对象的时候就会自动调用且只调用一次
pren(){
cout << "123" << endl;
}
};
void t1(){
pren p1;
}
int main(){
t1();
system("pause");
return 0;
}
类的使用
多文件使用需要添加::
void test::setx(int x){
x1=x;
}
类中可以使用另一个类作为本来中的成员
class pron{
public:
void setx(int x){
x1=x;
}
void sety(int y){
y1=y;
}
int getx(){
return x1;
}
int gety(){
return y1;
}
private:
int x1;
int y1;
};
class test{
public:
void getr(int r){
m_r=r;
}
int getr(){
return m_r;
}
void setcen(pron center){
mcenter=center;
}
pron getcen(){
return mcenter;
}
private:
int m_r;
pron mcenter;
};
类和结构体???
struct默认为公有权限
class默认为私有
类中的权限
class re{
//访问权限
//public 成员类内类外都可以访问
//protected 类内可以访问 类外不可以 儿子可以访问父亲的保护内容
//private 类内可以访问 类外不可以 不可以访问私有内容
public:
string name;
protected:
string car;
private:
int pass;
public:
void show(){
name="asdf";
car="wer";
pass=123;
}
}p1;
类与对象
封装,继承,多态
class student{
//权限
public:
//类中的属性和行为称为成员
//属性 成员属性 成员变量
string name;
int id;
//行为 成员函数 成员方法
//赋值
void add(string name){
s1.name=name;
}
void add(int id){
s1.id=id;
}
void show(){
cout << name << id << endl;
}
}s1;
int main(){
string name;
cin >> name;
s1.add(name);
int id;
cin >> id;
s1.add(id);
s1.show();
class yuan{
//权限
public:
//属性
int r;//半径
//行为通常使用函数
double clad(){
return 2*PI*r;
}
}y1;
int main(){
//yuan y1;
y1.r=100;
cout << y1.clad() << endl;
system("pause");
return 0;
}
函数重载中的参数引用及默认参数
void fun(int &a){ //使用fun(a);是这样传参的,int a =10; int &a=a;但是fun(10)为什么不行,参数是这样传的int &a=10;不合法
cout << "fun调用" << endl;
}
void fun(const int &a){ //使用fun(10);可以这样传参const int &a =10;引用常量可以指向常量的。
cout << "fun(int a)调用!" << endl;
}
int main(){
int a=10;
fun(a); //会调用fun(int &a);
fun(10);//调用fun(10);
system("pause");
return 0;
}
错误代码:
void fun1(int a,int b=10){
cout << "fun1" << endl;
}
void fun1(int a){
cout << "fun1" << endl;
}
int main(){
fun1(10);//函数重载遇到函数参数默认值会出现二义性
函数重载
让函数名相同,提高复用性
条件:
同一作用于(全在全局区里或者全在main函数里)
函数名相同
函数参数类型不同,或者个数或者顺序不同
函数返回值不可以作为重载条件
void fun(){
cout << "fun调用" << endl;
}
void fun(int a){
cout << "fun(int a)调用!" << endl;
}
void fun(double a){
cout << "fun(int a)调用!" << endl;
}
void fun(double a,int a){
cout << "fun(int a)调用!" << endl;
}
int main(){
fun();
fun(10);
system("pause");
return 0;
}
占位参数
占位参数也可以有默认参数
int a(int c,int = 20){
...
}
main(){
a(12,23);
}
占位参数
int a(int c,int){
...
}
main(){
a(12,23);
}
二义性
函数声明中如果有默认值则函数视线中就不可以用默认值
int a(int b=10;int c=10);
int a(int b=20,int d=20){
//编译器到底听谁的?????
}
函数的形参
形参可以有默认值
我使用fun函数可以传入自己的值如果没有就是用默认值
如果形参w有默认值,从w之后的形参都必须要有默认值
int fun(int q,int w=8,int e=1){
return q+w+e;
}
int main(){
int c=fun(3,2,3);
cout << c << endl;
到底是什么引用?
引用就类似于是一个指针常量
int * const p =&a; 等于 int &p=a;
左值
函数的返回值是引用,这个函数可以作为左值
t2函数返回的时候静态局部变量a
&r=a;
100也就是给变量a赋值同时别名r也随之改变
int &r=t2();
t2()=100;
int &t2(){
static int a=10;
return a;
}
函数返回值
重点!不可返回局部变量!!
可以在函数中使用static关键字作为静态局部变量,变量存放在全局区
t1函数返回局部变量第一次有效第二次就无效,因为局部变量在堆中存放
t2函数添加static关键字使变量放在堆中
int &t2(){
static int a=10;
return a;
}
int &t1(){
int a=10;
return a;
}
引用作为参数
函引用作为函数参数是和指针做参数效果相同
引用做参数也会修改原来的参数
如果不想被修改就是用const关键字
uu(a,b)
void uu(int &a,int &b)
void uu(const int &a,int &b)
引用
数据类型 &别名=原来的变量名
别名也可以是原名
别名和原名都是操作的同一内存
引用创建之前要初始化
初始化之后不可再次更改成其他变量的别名
New关键字
new申请数组
int *p=new int[10];//申请十个元素
for(int loop=0;loop<10;loop++){
p[loop]=loop+1;
}
释放数组
delete [] p;//释放数组要添加[]
申请堆区内存
int *p=new int(10);
new返回的是int类型的指针,返回的是地址,要用对应的类型指针来接住
使用delete释放内存
delete p;
释放后就不可再次访问
程序运行后
栈区是由编译器来分配释放(函数的参数和局部变量)
重点就是不要返回局部变量的地址,它是由编译器分配运行完自行释放
堆区由程序员来管理释放,程序结束由系统收回
使用new关键字在堆区申请内存
int *p=new int(10);
程序运行前分为全局区和代码区
代码区是共享的且只读的
全局区有全局/静态变量,常量
常量中有const的全局常量字符串常量
结构体数组
struct student{
string name;
int score;
};
struct teach {
string name;
struct student sarr[5];
};
void all(struct teach tarr[],int len){
string names="ABCDE";
for(int i=0;i<len;i++){
tarr[i].name="teach_";
tarr[i].name+=names[i];
for(int j=0;j<5;j++){
tarr[i].sarr[j].name="student_";
tarr[i].sarr[j].name+=names[j];
tarr[i].sarr[j].score=rand()%100;
}
}
}
void prin(struct teach tarr[],int len){
for(int i=0;i<len;i++){
cout << tarr[i].name << endl;
for(int p=0;p<5;p++){
cout << tarr[i].sarr[p].name << tarr[i].sarr[p].score << endl;
}
}
}
int main(){
srand((unsigned int)time(NULL));
struct teach tarr[3];
int len =sizeof(tarr)/sizeof(tarr[0]);
all(tarr,len);
prin(tarr,len);
防止误操作
加入const是给程序员看的
void prin(const struct *s1){
cout << s1->name << s1->age << s1->score << endl;
}
结构体的函数参数
prin()函数是值传递,形参和实参是分开的互不影响
prin2()函数是地址传参,形参修改实参也随之修改,并且需要使用指针来接收结构体的地址并且需要->来显示
struct student{
string name;
int age;
int score;
}s;
void prin(struct student s){
cout << s.name << s.age << s.score << endl;
}
void prin2(struct student *p){//使用指针来接收地址,要使用->来显示
cout << p->name << p->age << p->score << endl;
}
int main(){
s.name="asd";
s.age=20;
s.score=90;
//prin(s);
prin2(&s);
结构体中的结构体
struct student{
string name;
int age;
int score;
}s;
struct teach {
int id;
string name;
int age;
struct student s;
}t;
int main(){
t.id=100;
t.name="a";
t.age=290;
t.s.name="asd";
t.s.age=213;
t.s.score=4523;
cout << t.id << t.name << t.age << t.s.name << t.s.name << t.s.age << t.s.score << endl;
指针结构体
要使用结构体指针才能访问结构体 struct student *p = & s1;
要显示出指针结构体需要使用->符号 使用->符号 使用->符号
struct student {
string name;
int age;
int score;
};
int main(){
struct student s1= {"a",1,2};
struct student *p = &s1;
cout << p->name << p-> age << p->score <<endl;
结构体数组
先要创建一个结构体s3,然后在创建结构体数组s1,数组s1里面的格式按照结构体s3的顺序来写。
struct Student{
string name;
int age;
int score;
}s3;
struct Student arr[3]{
{"a",12,32},
{"b",32,453},
{"c",56,87}
}s1;
结构体
三种初始化方式
struct Student{
string name;
int age;
int score;
};
int main(){
struct Student s1;
s1.name="adsad";
s1.age=90;
s1.score=100;
cout << s1.name << s1.age << s1.score << endl;
struct Student{
string name;
int age;
int score;
};
int main(){
struct Student s2 = {"asfd",9,100};
cout << s2.name << s2.age << s2.score << endl;
struct Student{
string name;
int age;
int score;
}s3;
int main(){
s3.name="adsad";
s3.age=90;
s3.score=100;
cout << s3.name << s3.age << s3.score << endl;
指针函数
什么时候需要使用指针函数?
如果需要在传送参数之后并且更新变量就是用指针参数传递
指针参数传递完成或会修改原先的函数,变量a,b都会被修改掉!
传参的时候要传送变量的地址,传送的是地址!是地址!是地址!
要添加&取地址符号,在函数中要解引用*
void swap(int *num,int *num1)
{
...
}
int main(){
int a=10,b=20;
swap(&a,&b);
}
指针数组
*i是指针指向的变量值
i是指针指向变量的地址
i++,是在数组中连续的内存空间依次往下寻找下一个变量,之后就输出*i
指针
const修饰指针————常量指针
const就是告诉程序员们,这个常量不要轻易修改!
常量指针,变量为常量只不可以修改变量中的值但是可以指向其他变量。
int num = 10,num1 = 20;
const int *i = #
//此时,指针i不可以修改变量num的值,但是可以指向其他变量
i=&num1;
//指针i可以随意指向任意的变量唯独不可修改变量值
const修饰变量---------指针常量
指针可以修改变量值但不可以指向其他变量
int num=10,num1=20;
int * const i=#
//指针i现在指向变量num,此时可以修改变量num的值但不能指向其他变量
*i=100;
//num被赋值100,*i的值也是100;
//指针i唯独不可指向其他变量
const修饰指针和变量
意思是指针只能指向一个变量且不可修改变量内容
int num=10,num2=20;
const int * const i = #
野指针
指针指向非法空间
空指针
初始化指针变量,但不可以指向系统内存(系统内存编号在于0-255)
空指针不可访问
int *p = NULL;
指针
通过指针间接访问内存地址
指针是存放地址
指针前面的*叫做解引用
在32位系统下:指针占用4个字节
cout << sizeof(int *) << endl;
cout << sizeof(double *) << endl;
cout << sizeof(char *) << endl;
64位:占用8个字节
函数分文件编写
四步
1:创建.h头文件
2:创建.cpp源文件
3:在头文件中写函数声明(.h文件中)
4:在源文件中写函数定义(.cpp文件中)
第一步中要在头文件添加基本的头文件
//这是新建的.h头文件
//基本的头文件不可以丢失
#include <iostream>
using namespace std;
//函数声明
void swap(int ,int);
第二步要包括新创建的.h头文件
#include "你新创建的头文件.h"
编写你的函数
第三步在主函数中添加你新创建的头文件,这样你就可以调用新建cpp文件中的函数了
#include <iostream>
#include "新建头文件名.h"
using namespace std;
int mian(){
//这里就可以使用你新建cpp中的函数
}
函数样式
无参无返
无参有返
有参无返
有参有返
关于函数的值传递
使用函数的时候一定要声明函数
函数声明的意义就是告诉编译器,这里有一个函数,他是存在的在后面而已!
如何声明?
第四行为函数声明
#include <iostream>
using namespace std;
void swap(int ,int); //函数声明
void swap(int num,int num1){
cout << num << num1 << endl;
}
int main(){
swap(6,6);
return 0;
}
为什么要函数声明,加入我们将函数写到主函数之前,编译器是可以找到的,但如果在函数之后编译器是找不到函数的会报错。
形参改变不会影响到实参
一维数组的地址
怎么去数组的地址
int arry[5];
cout << (int)arry << endl;
cout << (int)&arry << endl;
&是取地址符号
数组名可以查看数组的长度,占用空间大小,以及数组的地址所,直接强制转换成int类型不需要取地址符号
又因为数组是在内存中,申请下连续的内存地址,当我取出数组名的首地址时,依次按照数组变量在内存中占用的空间大小就可以算出下一个数组变量的地址。
但要单一取出数组中变量的地址需要使用取地址符号&
一维数组
重点!
第一 :注意数组的长度!
第二 :要区分长度和位置初始值是不同的,数组的位置是从0开始,长度是从1开始数。
第三 :如果申请数组的长度为6,但是我只写入前三个数组的值,后面没有赋值的数组位置用0来补充。
continue语句
for(int num=0;num<100;num++){
if(num%2==0)continue;
else cout << num << endl;
}
continue语句与break不同之处在于
continue是终止当前循环,如上图代码,遇到偶数就终止这次循环执行下一个数字的判断
如果使用break就跳出循环不在执行下一个数字的判断
break语句
出现在switch语句中,终止case跳出switch,如果没有break语句就继续执行下一个case语句
跳出循环而不是终止当前循环,是跳出跳出跳出
在嵌套循环中使用break,是跳出最近的内层循环而不是一跃而出跳出所有循环。
for循环中的就近原则
for(int i=0;i<10;i++){
for(int i=0;i<10;i++)
cout << "* " << i << endl;
cout<<endl;
}
以上代码可以看到是双层for循环,循环变量是同一变量名
当我在循环中打印出变量i的时候,程序首先会选择离变量i最近的for循环来打印出现在变量i的内容
重点!不要轻易的在程序中是用这一方式!!!!
for循环执行方式
for(int num=0;num<100;num++){
cout << num << endl;
}
//首先先执行 num=0 第一步 1
//在进行判断 num<100 第二步 2
//在执行 cout << num << endl; 第三步 3
//最后执行 num++ 第四步 4
步骤就是:
123 234 234 234 ....
重点!!第一次执行for循环时不会执行num++,判断是否符合循环条件后直接执行循环内容
循环内容执行完毕后,再次进行判断,符合循环条件后,执行num++
随机数
rand()函数
使用方法
int num = rand()%100;
//在0-99中取随机数
//rand()%10,0-9中取随机数
int num =rand()%100+1;
//+1表示 随机数范围从0~99变成1~100
三目运算
int a,b;
cin >> a >> b;
(a>b?a:b)=100;
//a如果大于b,就给b赋值100否则就给a赋值100
cout << a << endl;
cout << b << endl;