目录
一,函数
1,函数的定义
函数在定义时使用默认参数必须从最后一个开始赋值,不允许存在从中间参数开始赋值,也不允许第一个参数开始赋值
//错误示例
①:void func(int a=10,b,c)
②:void func(int a,b=0,c)
//正确示例
①:void func(int a,b,c=10)
②:void func(int a,b=10,c=20)
2,函数的传参
给函数参数进行传参时也应该从末尾开始向前传参,不应该存在从开头或者中间开始传参的现象。
void func(int a ,int b=10)
{
printf("ok");
//printf("%d %d",a,b);
}
int main()
{
func(10); //给第一个参数传参,第二个参数不传参时就使用默认的参数,若传参就使用当前传入的参数,如果存在多个参数,只有最后一个参数有默认值时应该把所有的参数都传参。函数调用传参时时从第一个参数进行传参。
return 0;
}
3,函数的别名
//取别名
//使用别名就是使用这个变量名。
void swap(int & a,int & b)
{
int c=a;
a=b;
b=c;
}
int main()
{
int num;
float b;
num = 10;
b = 1.1;
printf("num=%d\n",num);
int & a = num;//对整型变量num取别名,别名为a; 类型 & 别名 = 被取别名的变量
a = 20;
printf("num=%d\n",num);//使用这个别名a就是使用变量num;
int c = 30;
a = c; //表示把c的值赋值给a,而不表示a这个引用变为c的别名;
printf("num=%d\n",num);
/*
int & c = b; //不同类型的变量不能使用取别名
b = 10;
printf("b = %d\n",b);
*/
int a1=10,a2=30;
swap(a1,a2);
printf("a1=%d a2=%d\n",a1,a2);
return 0;
}
4,函数重载
允许函数名同名,但是要保证函数的类型或函数的个数不一样。
int add(int a,int b)
{
return a+b;
}
double add(double a,double b)
{
return a+b;
}
double add(double a, double b,double c)
{
return a+b+c;
}
5,动态内存
动态内存的申请
格式:n ew 数据类型;即在堆空间中开辟对应数据类型的大小空间,并获得该空间的首地址。使>用对应类型的指标识符来存储该类型的地址。
释放动态内存空间:
格式:delete 需要释放的对应空间的地址。
#include<cstdio>
int main()
{
float *a = new float; //在空间中申请float类型大小的空间,同时得到这个空间的首地址。
int *b = new int; //like: int *b; b=new int;
*a= 10.1; //a为空间的首地址,*a为值。
printf("%f\n",*a);
delete a;
delete b;
return 0;
}
申请多个数据空间
格式:new 数据类型[ 需要申请的个数 ]
int main()
{
int *a = new int[10];
*a = 10;
*(a+1) = 20;
a[2] = 30;//数组名就是数组的首地址,所以可以用数组表示。
printf("*a=%d *a+1=%d a[2]=%d\n",*a,*a+1,a[2]);
//释放多个内存空间;格式:delete []对印的地址。
delete []a;
return 0;
//在申请空间时直接赋值 ,格式: new 数据类型(值);
int *c = new int(10);
printf("%d\n",c);
//对申请多个空间进行赋值。格式 :new 数据类型[需要申请的空间]{值};
float *d = new float[10]{1.1,1.2,1.3,1.4,1.5,1.6};
for(int i=0;i<=10;i++)
{
printf("%f\n",*d[i]);
}
}
二,输入输出
1,输出
使用c++标准库所提供的内容需要添加 using namespace std.
cout:输出,格式:cout<<需要输出的内容<<需要输出的内容<<...... 。
c++的换行符:① cout<<需要输出的内容<<'\n'
② cout <<需要输出的内容<< endl;
#include<cstdio>
#include<iostream>
using namespace std;
int main()
{
//输出
int a=20;
cout<< a <<'\n';
cout<<"a= "<< a <<'\n';//like:cout<< "a= "; cout<< a ; cout << '\n';
//endl = '\n'
cout<< "a= "<< a <<endl;
char *p = "nihao";
cout << p <<endl; //此时不能打印地址而是打印字符串。
cout <<(void *)p<<endl; //需要打印地址应该这样操作。
}
2,输入
cin: 输入 格式:cin >>需要输入的变量;
#include<cstdio>
#include<iostream>
using namespace std;
int main()
{
//输入
int a;
cin >> a; //单个输入
cout<< a<<endl;
int a1,a2; //多个输入
cin>>a1>>a2;
cout<< a1 << a2 <<endl;
cout<< a1 <<" "<< a2 <<endl; //添加空格输出。
}
三,类与对象
1,类的概念
抽象的描述一类事物就叫类。
2,类的创建
描述事物具有一定的特征和行为。
编写类的基本语法
calss 类名
{
特征----属性-->变量表示
行为----方法-->函数表示
};
3,对象的概念
类中的一种事物,包括对象的行为和特征。
4,对象的创建
类名 变量对象名
对象的使用:①:对象名 . 成员名;
②:对象指针->成员名;
5,类的成员访问
#include <iostream>
//描述一个人。
class people
{
//特征
char name[20];
int age;
char sex;
//行为
void eat()
{
cout<<"eat sth"<<endl; //描述吃饭
}
void sleep()
{
cout<<"sleep"<<endl; //描述睡觉
}
}; //不占用内存空间,是对一类型的说明,是对一类事物抽象的表示
using namespace std;
int main()
{
people p1; //创建实例化对象 存在于堆;like :char *pe1 = new people
cout << "Hello World!" << endl;
return 0;
}
四,构造函数
1,构造函数
构造函数 ,是一种特殊的方法。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载。
构造函数的命名和类名完全相同,没有返回值,在定义一个类时,通常都会有默认的构造函数,但默认的构造函数不带参数。
格式1:
class <类名>
{
public:
<类名>(参数表);
};
格式2:
<类名>::<函数名>(参数表)
{
//函数体
}
2,析构函数
析构函数是指当对象在结束生命周期时,系统自动执行析构函数,用于释放内存。其没有参数,也没有返回值,有且只有一个析构函数,不能重载,没有编写析构函数,在编译时系统也会自动生成一个缺省的析构函数。
格式:
class <类名>
{
public:
~<类名>(); //~就代表着析构函数
};
<类名>::~<类名>()
{
//函数体
}
3,拷贝构造函数
一种特殊的构造函数,由编译器调用来完成一些基于同一类的其他对象的构建及初始化。
拷贝函数调用的情况:
①:一个对象作为函数参数,以值传递的方式传入函数体。
②:一个对象作为函数返回值,以值传递的方式从函数返回。
③:用于给对象进行初始化。
格式:
类名 (const 类名 &obj) {成员 = obj . 成员}
4,this指针
不属于对象的一部分,不影响对象的大小,作用域类内部,不需要用户编写。
五,关键字
1,const
const 限定符,用于将对象转为一个常量。
①:const int *p=1 *p不可改变,但是p可以改变
②:int *const p=1 p不可改变,但是*p可以改变
③:const int* const p=1 都不可以被改变。
2,static
用于修饰静态成员函数,函数属于整个类,所有的对象都使用同一个函数,相当于没有this指针,在静态成员函数中只能访问静态变量。
六,友元,继承与多态
1,友元
友元是一种定义在类外部的普通函数或类,但需要在类体类进行说明,友元不是成员函数,但是可以访问私有成员。定义时在前面加上关键字friend。
友元关系不能被继承,且友元关系是单向的,不具有交换性,更不具有传递性。
class a
class b
{
friend class a
};
2,继承
基类(父类):已经存在的类。
子类(派生类):新建的类
继承:子类从父类哪里获得父类的特性
一个基类可以派生出很多个子类,一个子类也可以派生出很多个子类。
在子类中,不会继承父类的构造函数和析构函数(派生类拥有自己的构造函数和析构函数)基类和子类的属性各不相同。
继承的方式
①:公有继承
②:保护继承
③:私有继承
子类构造函数的执行顺序 :先执行基类的构造函数 再执行子类的构造函数
子类析构函数的执行顺序:先执行子类的析构函数 在执行父类的析构函数
3,多态
虚函数:被virtual修饰的成员函数,可实现成员函数的动态重载。
格式:virtual 函数返回类型 函数名 (参数表){函数体};
定义虚函数的限制:
①:非类的成员函数不能定义为虚函数,类的成员函数中的静态成员函数和构造函数也不能定义为虚函数,但析构函数可以定义为虚函数。
②:只要在类中将函数声明为虚函数后,在定义时就不用再次定义。
③:将基类中的某一成员函数定义为虚函数后,派生类的同名函数(同名函数:函数名相同,参数列表一致,返回值类型一样)也将自动称为虚函数。
④:如果派生类需要使用基类的接口,派生类需要和基类 的虚函数完全一致。
纯虚函数:
一种特殊的虚函数,自身没有函数的实现,需要派生类去实现,具有自身的函数名,参数和返回值类型,但不具有函数体。
抽象类:
包含纯虚函数的类称为抽象类,抽象类没有完整的信息,只能是派生类的基类,抽象类中不能存在静态成员
多态:一个接口多个方法,为不同数据类型的实体提供统一的接口。
七,异常处理,转化函数和STL
1,异常处理
目的:抛出程序在执行期间产生的问题。
关键字:
try:检查程序中异常,存在异常就交给catch处理,其后面跟随着一个或者多个catch块。
catch:捕获异常
throw:抛出异常
格式:
try
{
if(错误)
{
throw //抛出异常
}
}catch(捕获异常)
{
//抛出异常
}
2,转化函数
一种特殊类型的类成员函数,用以将当前类对象转化为其它类型的类对象。
格式:operator 当前类型 (){转换方式 return 转换后的类型。
#include <iostream>
using namespace std;
class intager
{
private:
int num;
int num1;
int num2;
public:
operator float() //将当前类类型转化为其他类型。
{
num2=10;
int n = num1 + num2;
return float(n);
}
operator int()
{
cout<<"operator int"<<endl;
return num;
}
intager(int n) //将其他类型转化为当前类类型。
{
num = n;
}
int getvalue()
{
return num;
}
void setvalue(int n)
{
num = n;
}
void showvalue()
{
cout<<"value is : "<<endl;
}
};
int main()
{
cout << "Hello World!" << endl;
/*
int a;
float b;
a = 10;
b = 2.1;
cout<<a+b<<endl;
b = a; //隐式转化
cout <<b<<endl;
a = b; //不能实现转化为小数
cout<<a<<endl;
*/
int val = 97;
char ch;
ch = char(val);
cout<<ch<<endl;
intager a;
a.setvalue(10);
intager b;
b.setvalue(100);
int d = b;
cout<< d <<endl;
intager e;
e.setvalue(1000);
return 0;
}
3,STL
一种标准模板库。
函数模板格式:
template<typename G,typename T,typename F> //表示G T F都是类型参数
G add(T a, F b)
{
return a+b;
}
例子:
#include <iostream>
using namespace std;
/*
template<typename T,typename F> //表示T F都是类型参数
T add(T a, F b)
{
return a+b; //不要使用 ①
}
*/
template<typename Q=int,typename W=int,typename E=int> //表示G T F都是类型参数
Q add(W w, E e)
{
return w+e; //直接定义类型 ②
}
//函数的功能一样,函数的参数不同,就可以使用函数模板,函数模板只能在全局函数中使用
//模板函数
//template<typename G,typename T,typename F> //表示G T F都是类型参数
//G add(T a, F b)
//{
// return a+b;
//}
/*
int add(int a ,int b)
{
return a+b;
}
double add(int a,double b)
{
return a+b;
}
int add(double a ,int b)
{
return a+b;
}
*/
template<typename A,typename B,typename C,typename D> //表示G T F都是类型参数
D add(A a, B b,C c)
{
return a+b+c;
}
/*
int add(int a ,int b,int c)
{
return a+b+c;
}
double add(double a,double b,double c)
{
return a+b+c;
}
*/
int main()
{
// cout << "Hello World!" << endl;
// cout<<"int is: "<<add<int,int,int>(1,2)<<endl;
// cout<<"double is: "<<add<double,int,double>(1.1,3)<<endl;
// cout<<"double1 is: "<<add<double,int,int,double>(1.1,2,3)<<endl;
//cout<<add(1,2)<<endl; //不要使用
cout<<"value is: "<<add(3,2)<<endl; //已经定义类型就是用默认类型 ②
return 0;
}