一.C++版本对比C版本的hello world 输出
1.编写C++程序
c++程序必须要有一个main函数,也就是程序的入口函数,操作系统调用该函数来执行程序,main必须是小写
函数的组成部分:函数名称,返回值,形参列表,函数体
// c 版本的程序
#include<stdio.h> // 标准输入输出
#include<stdlib.h>
int main()
{
printf("hello world\n");
system("pause");
return 0;
}
//c++版本的程序
#include<iostream>//包含io库下的std::cout
int main()
{
//标准命名空间 ostream = outstream
std::cout<<"hello world!"<<std::endl;
system("pause"); //暂停,便于调试
return 0; //函数的返回值
}
2.输入和输出
C语言中使用prinf和scan进行输入输出,C++使用标准库中的IO流实现
Iostream中四个IO对象:输入cin输出cout错误cerr日志clog
//输入2个数求和,并打印出2个数的和
#include<iostream>
//std 为命名空间 namesapce,防止相同文件名的命名冲突
int main()
{
int a,b,sum;
std::cout<<"输入2个数:"<<std::endl;
std::cin>>a;//后台输入的数
std::cin>>b;
//或者用std::cin>>a>>b;
sum=a+b;
std::cout<<a<<"+"<<b<<"="<<sum<<std::endl;
system("pause");
return 0;
}
3.流程控制
3.1 if else的判断
#include
int main()
{
//1.顺序执行
int pwd;
int count=0;
std::cout<<“请插入卡:”<<std::endl;
std::cout<<“请输入密码:”<<std::endl;
//2.做出选择
std::cin>>pwd;
if (pwd == 123)
{
std::cout<<“取钱1000”<<std::endl;
}else{
std::cout<<“密码错误,重新输入,你还有”<<3-count<<“次机会!”<<std::endl;
//循环三次2
while(++count<=3){
std::cin>>pwd;
if (pwd==123)
{
std::cout<<“取钱1000”<<std::endl;
break;
}else{
if(count<3)
{
std::cout<<“密码错误,重新输入,你还有”<<3-count<<“次机会!”<<std::endl;
}else{
std::cout<<“三次密码错误,您的卡已经被锁定!”<<std::endl;
}
}
}//end while
}//else
system("pause");
return 0;
}//main()
3.2 三元运算
//三元运算:
#include<iostream>
int main()
{
int a=1,b=2;
int max=a>b?a:b;
std::cout<<max<<std::endl;//2
system("pause");
return 0;
}
3.3 for循环
#include<iostream>
int main()
{
int sum=0;
for (int i=0;i<=10;i++){
if (i!=2){
sum=sum+i;
}else{
continue;
}
}//end for
std::cout<<sum<<std::endl;//53
system("pause");
return 0;
}//end main
4.类对象介绍
4.1类的定义和声明
可以自己定义类型
自己定义get()set()方法
#include<iostream>
#include<string>
using namespace std;
//成员函数
class Person{
private:
int _pid;
string _name;
int _age;
public:
void setpid(int pid);
int getpid();
void setname(string name);
string getname();
void setage(int age);
int getage();
};
void Person::setpid(int pid)
{
_pid=pid;
}
int Person::getpid()
{
return _pid;
}
void Person::setname(string name)
{
_name=name;
}
string Person::getname()
{
return _name;
}
void Person::setage(int age)
{
_age=age;
}
int Person::getage()
{
return _age;
}
int main()
{
Person per;
per.setpid(1);
per.setname("Tom");
per.setage(20);
int pid=per.getpid();
string name=per.getname();
int age=per.getage();
per.getage();
cout<<pid<<","<<name<<","<<age<<endl;
system("pause");
return 0;
}//end main
构造函数:在实例化对象的时候调用Person()
析构函数:清除对象的时候调用~Person()
#include<iostream>
#include<string>
using namespace std;
//成员函数
class Person{
private:
int _pid;
string _name;
int _age;
public:
//构造函数
Person();
//析构函数
~Person();
void setpid(int pid);
int getpid();
void setname(string name);
string getname();
void setage(int age);
int getage();
};
Person::Person()
{
cout<<"构造函数"<<endl;
}
Person::~Person()
{
cout<<"析构函数"<<endl;
}
void Person::setpid(int pid)
{
_pid=pid;
}
int Person::getpid()
{
return _pid;
}
void Person::setname(string name)
{
_name=name;
}
string Person::getname()
{
return _name;
}
void Person::setage(int age)
{
_age=age;
}
int Person::getage()
{
return _age;
}
int main()
{
/*
Person per; //构造函数
per.setpid(1);
per.setname("Tom");
per.setage(20);
int pid=per.getpid();
string name=per.getname();
int age=per.getage();
per.getage();
*/
//指针的方式
Person *per=new Person();//构造函数
per->setpid(1);
per->setname("Tom");
per->setage(12);
int pid=per->getpid();
string name=per->getname();
int age=per->getage();
cout<<pid<<","<<name<<","<<age<<endl;//1,Tom,12
delete per; //析构函数
system("pause");
return 0;
}//end main
关于头文件和源文件的使用:
per.h文件
#include<iostream>
#include<string>
using namespace std;
//定义写到头文件中
class Per
{
private:
int _pid;
string _name;
int _age;
public:
void setpid(int pid);
int getpid();
void setname(string name);
string getname();
void setage(int age);
int getage();
};
Per.cpp文件
#include "per.h"
//调用头文件,实现在源文件
void Per::setpid(int pid)
{
this->_pid=pid;
}
int Per::getpid()
{
return _pid;
}
void Per::setname(string name)
{
this->_name=name;
}
string Per::getname()
{
return _name;
}
void Per::setage(int age)
{
this->_age=age;
}
int Per::getage()
{
return _age;
}
test.cpp文件
#include<iostream>
#include<string>//系统库用尖括号
#include "Per.h"//自己的使用双引号
using namespace std;
int main()
{
Per per; //自定义;类型
per.setpid(1);
per.setname("Tom");
per.setage(20);
int pid=per.getpid();
string name=per.getname();
int age=per.getage();
per.getage();
cout<<pid<<","<<name<<","<<age<<endl;//1,Tom,12
system("pause");
return 0;
}//end main
二.数据类型
1.基本数据类型
包括:整数,浮点数,字符,布尔值,void
整型:int(1个字长) long(2个字长) short(半个字长)
浮点数:float double
字符:char 单引号括起来,可以与整型互换
bool:可以是true(非零数) false(零)
void表示无返回值,void*表示任意的对象类型
Test.cpp
#include<iostream>
#include<string>//系统库用尖括号
using namespace std;
int main()
{
//布尔类型
bool flag=true;
cout<<flag<<endl;//1
flag=false;
cout<<flag<<endl;//0
//字符类型
char c='A';
cout<<c<<endl;//A
//字节大小
cout<<sizeof(c)<<endl;//1
//短整型
short s=100;
cout<<s<<endl;//100
cout<<sizeof(s)<<endl;//2
//长整型
long l=2345;
cout<<l<<endl;//2345
cout<<sizeof(l)<<endl;//4
//浮点型
float f=3.14;
cout<<f<<endl;//3.14
cout<<sizeof(f)<<endl;//4
//无符号类型
unsigned int ui=123;
cout<<ui<<endl;//123
cout<<sizeof(ui)<<endl;//4表示4字节,32位
system("pause");
return 0;
}//end main
2.字面常量
为基本数据类型赋值的结果成为字面常量。例如int i=10;10被成为字面常量。
转义字符:\n\t\r\b 换行,table键 ,回车,退格
\’ \” 输出单引号双引号
3.变量
变量是内存里的一块存储区域,为该存储区域起一个名字name,age,通过这个名字可以操作这块存储区域,可以获得/修改它的值。
C++是一门静态类型的语言,编译时做类型检查,要求我们在定义变量的时候必须指定类型;类型决定了变量的内存大小和布局,取值范围,以及应用于该变量上的操作。
变量的初始化:是指定义变量的时候为变量赋值。分为:直接初始化(括号)或者拷贝初始化(等号赋值)。
函数体外部的被定义为0,函数体内的必须初始化。
类的初始化是调用构造函数。
变量的定义和声明:变量的定义用于为变量分配存储空间,还可以为变量赋值,变量只能定义一次。声明用于向程序说明变量的类型和名称,声明的时候不会分配存储空间。
例子说明:
#include<iostream>
#include<string>//系统库用尖括号
using namespace std;
int out; //函数体外部定义的
int main()
{
//1.变量
int age=23;
//2.变量的命名
string custume_name;
string _name;
int _age;
//3.初始化
int pid=1; //拷贝初始化
int pid1(2); //直接初始化
//4.初始化规则
int in; //函数内部定义的,没有初始化,不用不报错,用了就报错。
cout<<out<<endl;//默认是0
//cout<<in<<endl; //函数体内部必须初始化,没赋值会报错
//5.变量的定义和声明
int x=100; //定义:声明的同时初始化了
extern int y; //声明
system("pause");
return 0;
}//end main
4.const的用法
(1)变量前面使用const关键字,表示该变量不可以被修改,即该变量是一个常量。
#include<iostream>
#include<string>//系统库用尖括号
using namespace std;
int main()
{
//左值必须是可修改的,等号右边是右值
int age=20;
cout<<age<<endl;//20
age=21;
cout<<age<<endl;//21
system("pause");
return 0;
}//end main
(2)使用常量的好处:一是程序的可读性强,二是程序更容易被维护。
例如:
#include<iostream>
#include<string>//系统库用尖括号
using namespace std;
int main()
{
//int arr[4*6];这样可读性差
const int size=4*6;
int arr[size];
system("pause");
return 0;
}//end main
(3)const默认为文件的局部变量,
全局作用域中的非const变量的作用域是全局的。
例如:
Per.cpp文件中
int a=100;//这样不报错
//const int a=100;这样使用会报错
Test.cpp文件 中
#include<iostream>
#include<string>//系统库用尖括号
using namespace std;
int main()
{
extern int a;//没有extern会报错的
cout<<a<<endl;//100
system("pause");
return 0;
}//end main
5.引用
(1)引用就是变量的别名,通常在函数的形参列表中
(2)定义引用的语法格式是在变量前面加“&”符号
例子:
//注意应用必须赋初始值
int a=100; //a表示张三
int &r=a; //r是张三的别名小张
cout<<r<<endl;//100
例子:
#include<iostream>
#include<string>//系统库用尖括号
using namespace std;
//copy 只是复制,没有实现交换
void swap(int a, int b)
{
int temp;
temp=a;
a=b;
b=temp;
cout<<"a="<<a<<",b="<<b<<endl;
}
//reference 引用,用在函数的形参里面
void swap2(int &a,int &b)
{
int temp;
temp=a;
a=b;
b=temp;
cout<<"a="<<a<<",b="<<b<<endl;
}
int main()
{
int a=1,b=2;
swap(a,b); //a=2,b=1
cout<<"a="<<a<<",b="<<b<<endl;//a=1,b=2
swap2(a,b); //a=2,b=1
cout<<"a="<<a<<",b="<<b<<endl;//a=2,b=1
system("pause");
return 0;
}//end main
6.类型定义
(1)typedef 用来定义类型的同义词,typedef int myint ;myint age;
(2)语法格式:typedef 数据类型 标识符
目的:
隐藏特定类型的实现,强调使用类型的目的;
简化复杂类型的定义,使其更容易被理解;
允许一种类型用于多个目的,同时使得每次使用该类型的目的明确;
例子:
#include<iostream>
#include<string>//系统库用尖括号
using namespace std;
//类型定义:可以包括内置类型or类or结构体
//结构体
typedef struct MyStruct{
int x;
int y;
}Point;
typedef class Person{
public:
int pid;
}Teacher;
int main()
{
//Teacher代表类
Teacher t;
t.pid=2;
cout<<t.pid<<endl;//2
//内置类型
typedef int myint;
myint age;
myint pid;
//Point代表结构体
Point p;
p.x=1;
p.y=2;
cout<<p.x<<p.y<<endl;//12
system("pause");
return 0;
}//end main
7.枚举
使用enum关键字定义有关联性的枚举类型
枚举成员是常量是,默认从0开始,也可以赋值;
例子:
#include<iostream>
#include<string>//系统库用尖括号
using namespace std;
enum direction{
up,
down,
left1=100,
right1
};//注意内部使用逗号,结束使用分号
int main()
{
//枚举类型的第一个值默认从0开始
cout<<up<<endl; //0
cout<<down<<endl; //1
//如果对某一个赋值,那么其后的依次一次递增,之前的仍是默认值
cout<<right1<<endl; //101
system("pause");
return 0;
}//end main
例子2:
#include<iostream>
#include<string>//系统库用尖括号
using namespace std;
enum direction{
up,
down,
left1=100,
right1
};//注意内部使用逗号,结束使用分号,常量一般用大写
void change(direction d){
switch (d){
case up:
cout<<"up"<<endl;
break;
case down:
cout<<"down"<<endl;
break;
case left1:
cout<<"left"<<endl;
break;
case right1:
cout<<"right"<<endl;
break;
default:
break;
}// switch end
}
int main()
{
change(up);//up
system("pause");
return 0;
}//end main
8.自定义类型
(1)类也是一种类型,使我们自己定义的一种类型;
(2)设计一个类的时候,先设计类的接口interface,再设计类的实现implementation;
(3**)接口是给客户来调用的,可以将类的接口定义在头文件(.h)中,类的实现定义在源文件(.cpp)中,并在源文件中包含头文件。**
例子:
per.h头文件
#include<iostream>//用到输入输出
#include<string>//用到字符串
using namespace std;
//接口写到头文件中
class Per
{
private:
int _pid;
public:
void setpid(int pid);
int getpid();
};
class Pet
{
private:
int _pid;
public:
void setpid(int pid);
int getpid();
};
Per.cpp源文件:
#include "per.h"
//实现接口 注意PerPet大写是指的per.h中的类名Per,Pet
void Per::setpid(int pid){
//this是对当前对象的引用
this->_pid=pid;
}
int Per::getpid(){
return _pid;
}
void Pet::setpid(int pid){
this->_pid=pid;
}
int Pet::getpid(){
return _pid;
}
Tets.cpp源文件
#include<iostream>
#include<string>//系统库用尖括号
#include "per.h"
using namespace std;
struct MyStruct{
int x;
int y;
//void func();//结构体内不可以定义函数
};
int main()
{
Per p1;
Pet p2;
p1.setpid(20);
p2.setpid(100);
cout<<p1.getpid()<<endl; //20
cout<<p2.getpid()<<endl; //100
system("pause");
return 0;
}//end main
三.sting and vector
1.命名空间
在文件系统中不能有2个同名的文件,这样会产生命名冲突。
命名空间解决命名冲突问题,关键字是namesapce
格式:
namespace名称{
变量,常量,函数等的定义
}
使用域访问符号“::”访问命名空间中的成员
例子:
#include<iostream>
#include<string>//系统库用尖括号
using namespace std;//系统定义好的命名空间
namespace MyNS1{
//自定义命名空间中可以定义变量方法函数
int a;
int b;
void f1();
class Person{
public:
void f2();
};
}
void MyNS1::Person::f2(){
cout<<"f2"<<endl;
}
void MyNS1::f1(){
cout<<MyNS1::a<<","<<MyNS1::b<<endl;
}
using namespace MyNS1;//使用这一行可以代替下面MyNS1::
int main()
{
a=100;
b=200;
f1();
Person per;//100,200
per.f2();//f2
/*
MyNS1::a=100;
MyNS1::b=200;
MyNS1::f1(); // 100,200
MyNS1::Person per;
per.f2();//f2
*/
system("pause");
return 0;
}//end main
2.string字符串
(1)C语言中使用字符数组;来表示字符串,
C++中提供string类来操作字符串;string支持长度可变的字符串,c++标准库负责管理与操作字符相关的内存,并提供各种有用的操作。
(3)使用string类需要包含string类头文件和std命名空间,
#include
using namespace std;
2.1字符串的定义和初始化:
void test1(){
string s;//默认构造函数,s1为空
string s2(s);//将s2初始化为s1的一个副本
string s3(“hello,world”);//将s3初始化为hello,world
string s4(2,‘a’);//将s4初始化为2个a字符的字符串
}
2.2字符串的读写
2.2.1例子:cin cout
#include
#include//系统库用尖括号
using namespace std;//系统定义好的命名空间
void test2(){
string s;
cout<<“please type string:”<<endl;
cin>>s;
cout<<s;
}
int main()
{
test2(); //输入hello world 输出hello空格之后的不能输出
system(“pause”);
return 0;
}//end main
2.2.2例子:循环读写
void testString(){
string s1;
while(cin>>s1){
cout<<s1<<endl;
if (s1==“bye”){
break;
}
}
}
2.2.3例子:getline
void getLine(){
string line;
cout<<“please type string:”<<endl;
while(getline(cin,line)){//读取cin的内容存到line
cout<<line<<endl;
if(line == “bye”){
break;
}
}//end while
}
2.3字符串的操作
判断是否为空,获取字符串长度。获取某个位置的字符
void test4(){
string s(“hello”);
bool result=s.empty();
cout<<result<<endl;//0
int size=s.size();
cout<<size<<endl;//5
char c=s[1];
cout<<c<<endl;//e
}
连接+ 比较2个字符串是否相等用==
3.vector向量
3.1介绍
向量是一种随机访问的数据类型,提供了对数组元素的快速,随机访问以及在序列尾部快速随机的插入和删除操作,是大小可变的向量。
3.2向量中常用方法
front:返回向量起始元素的引用
end:返回向量末尾元素的引用
begin:返回向量中第一个元素的迭代器
size:返回向量的大小
capacity:返回当前向量最多可以容纳的元素个数
clear:清除向量
insert(i,x):元素x插入到迭代器i所指的位置
empty:判断向量是否为空
erase(i):删除迭代器所指向的元素
erase(start,end):删除迭代器start和end范围内的向量元素
pop_back:删除向量中最后一个元素
push_back(x):在向量末尾添加x元素
例子:
#include
#include//系统库用尖括号
#include
using namespace std;//系统定义好的命名空间
int main()
{
vector v;
vector v1;
vector v2;
vector v3;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
//iteration 迭代器遍历
vector<int>::const_iterator it = v.begin();
while(it!=v.end()){
//*指的是指针,++优先级更高
cout<<*it++<<endl; //输出1-5
}
/*
//for循环遍历
int size=v.size();
for(int i=0;i<size;i++){
cout<<v[i]<<endl; //输出1-5
}*/
cout<<"遍历结束!"<<endl;
cout<<v.front()<<endl; //1
cout<<v.back()<<endl; //5
it=v.begin();
v.erase(it+2);
cout<<v.size()<<endl; //4
system("pause");
return 0;
}//end main
四.数组和指针
1.数组
(1)数组可以保存相同的数据元素,长度是固定的;指针可以像迭代器一样遍历数组。
(2)数组是包含多个数据值(元素)的数据结构;每个数据值的类型相同;
(3)声明:说明类型的元素数量;int a[10]
(4)初始化:带有{}的常量列表;int a[]={1,2,3,4,5}
(5)访问:索引访问,下标是0开始;
for(int i=0;i<n;i++){}
例子:
#include
#include//系统库用尖括号
using namespace std;//系统定义好的命名空间
class Person(){
};
//1.数组保存基本数据类型
void test1(){
const int size=10;
int a[size];
for(int i=0;i<size;i++){
a[i]=i+1;
}
cout<<a[0]<<endl;
}
//2.保存类 类型
void test2(){
const int size=2;
Per pers[size];
per p1;
Per p2;
pers[0]=p1;
pers[1]=p2;
}
int main()
{
test1();//1
system(“pause”);
return 0;
}//end main
2.指针
(1)指针也是一种变量,是指向另一种变量地址的变量。
保存的值是另一种变量的地址。
(2)作用:使用指针可以间接的操作指向的变量对象。
#include
#include//系统库用尖括号
using namespace std;//系统定义好的命名空间
void test1(){
int i=100;
int *ip = &i; // *解引用,&取地址
cout<<i<<endl; //对象本身 100
cout<<*ip<<endl; //对象本身 100
cout<<&i<<endl; //地址
cout<<ip<<endl; //地址
}
(3)声明:2种: int ip; int ip;
(4)指针的可能取值:
某个对象的地址;0值;指向某个对象后面的另外一个对象,用来操作数组。
#include
#include//系统库用尖括号
using namespace std;//系统定义好的命名空间
void test2(){
int a=100;
int *ad = &a;//另外一个变量的地址
int *p = 0;//不指向任何对象
int *q = NULL;//define NULL 0
const int x=0;
int *ip = x;// x=0 ok x=1 error
//int y=0;
//int *iq=y;//error 不是常量
int arr[] = {1,2,3};
int *ap = arr;//等同于 int *ap = arr[0]; 数组名称代表数组首地址
cout<<*ap<<endl;//1
ap++;
cout<<*ap<<endl;//2
}
(4)void 指针 可以保存任何类型对象的地址
#include
#include//系统库用尖括号
using namespace std;//系统定义好的命名空间
void test3(){
int i=100;
void p = &i;
double d = 200;
void* q = &d;
}
//方法的返回值类型
void* test4(){
int i=100;
return &i;
}
//用于方法的形参
void test5(void* v){}
class Person(){};
int main()
{
Person *p=new Person();
test6§;//形参传递的类的对象
system("pause");
return 0;
}//end main
(5)指针的引用的区别:
引用总是指向某个对象,定义引用时没有初始化是错误的;初始化后不可以改变。
赋值行为的差异:给引用赋值修改的是引用所关联的对象的值,并不是引用与另外一个对象关联。
void test7(){
int i = 100;
int j = 200;
int &q = i; //引用必须初始化,初始化后不可改变,引用就是变量的别名
int *p; //指针可以不初始化
p = &i; //指针可以再赋值
p = &j;
}
void test8(){
int i = 100,j = 200;
int &pi = i, &pj = j;
cout<<“i=”<<i<<",j="<<j<<endl; //i=100,j=200
cout<<“pi=”<<pi<<",pj="<<pj<<endl; //pi=100,pj=200
cout<<"------------"<<endl;
pi = pj;//相当于i=j 指针的赋值指同一个对象,引用的赋值是它本身
cout<<“i=”<<i<<",j="<<j<<endl; //i=200,j=200
cout<<“pi=”<<pi<<",pj="<<pj<<endl; //pi=200,pj=200
}
(6)二级指针
void test8(){
int i=100;
int *p=&i;
int **q=&p;
cout<<p<<endl;//地址
cout<<*q<<endl;
}
(7)指向const对象的指针
void tes(){
const float *ppi;
const float pi=3.14;
ppi=π//pi是指向const对象的指针
cout<<*ppi<<endl; //3.14
}
//const指针,指针本身不能被修改
void test1(){
int i=100,j=200;
int *const pi=&i;
cout<<*pi<<endl;//100
}
//指向const对象的const指针
void test2(){
//两者都不能被修改
const double pi=3.14;
const double const pi_p = π
}
五.运算符和表达式
1.算数运算
算数运算符:加 减 乘 除 取余
运算符分类:
一元运算符:取地址&,解引用
二元运算符:加 减等
三元运算符:int max = i > j ? i : j
作用于内置类型,或者通过与运算符重载来操作类类型。
2.关系运算和逻辑运算
3.位运算
与 and &
或 or |
非 not ~
异或 xor ^ 相异为1
4.赋值运算
赋值运算的左值必须是非const的
5.自增自减运算
前置先计算后赋值;后置先复制后计算。
void test(){
int i=0,j=0;
cout<<++i<<endl; //1
cout<<j++<<endl; //0
}
//两次遍历1-5相同的效果,迭代器本身就是一种指针。
void test(){
const int length=5;
int arr[]={1,2,3,4,5};
for(int i=0;i<length;i++){
cout<<arr[i]<<endl;
}
cout<<"--------------"<<endl;
int *p = arr;
for(int i=0;i<length;i++){
cout<<*p++<<endl;
}
}
5.new 和delete
(1)使用new 和delete动态的创建和释放数组/单个对象。
class Person(){};
void test(){
int *i=new int();
string *s=new string(“hello,world”);
Person per;
Person *p=new Person();
//delete释放内存地址,但是仍然指向一个对象
delete i;
delete s;
delete p;
}
(2)new在自由存储区分配并创建一个对象,返回对象的地址(指针),我可以通过指针访问对象。
(3)动态创建对象的初始化,可以像初始化变量的方式来初始化,
class Person(){
public:
int pid;
int getpid();
};
void test(){
int *i=new int();
string *s=new string(“hello,world”);
Person per;
Person *p=new Person();
p->pid=100;
p->getpid();
//delete释放内存地址,但是仍然指向一个对象
delete i;
delete s;
delete p;
i=NULL; //重置指针,表示没有指向任何对象
}
(4)自由存储区被耗尽的时候,系统会抛出bad_alloc异常,也就是内存溢出,所以当我们使用new分配内存后,应该及时使用delete删除,释放内存。
使用delete之后,需要重置指针,否则指针还是指向原来的对象,这种指针称为悬垂指针。
(5)const对象的动态分配和释放与非const对象相同。
六.流程控制
1.简单语句
分号结尾,定义一个语句或者一个变量,空语句是只有一个分号;
复合语句:多个语句组成。block块。
//空语句的使用
void test(){
string s;
cout<<“输入一个字符串:”<<endl;
//第一种 更简洁
while(cin>>s&&s!=“bye”);
//第二种
while(cin>>s){
if(s==“bye”)break;
}
}
//空语句的使用
void test2(){
vector v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
vector<int>::const_iterator it=v.begin();
while(it!=v.end())
cout<<*it++<<endl;
}
2.声明语句
定义define和声明statement是有区别的:
int i;//表示定义一个变量
extern int j;//加了extern表示前面已经定义过这个变量,在这只是声明
class Person; //前导声明,只是用到类的名称,还没有定义类
class Person{}; //statement语句,语句必须分号结束
3.复合语句(block块语句)
函数体,方法体
4.条件语句
判断语句:
if else; switch;三元运算;
//判断三个数谁最大
void test(){
int a=100,b=1,c=2;
if(a>b){
if(a>c){
cout<<“a最大”<<endl;
}else{//c>a
cout<<“c最大”<<endl;
}
}else{//b>a
if(b>c){
cout<<“b最大”<<endl;
}else{//cbc
cout<<“c最大”<<endl;
}
}
}
5.循环语句
while;do while;for循环
例子while:
void test(){
int sum=0;
int i=1;
while(i<10){
sum=sum+i;
i++;
}
printf(“sum=%d\n”,sum);//sum=45
}
例子:for循环实现乘法表
void test(){
for(int i=1;i<=9;i++){
for(int j=1;j<=i;j++){
printf("%d*%d=%d “,j,i,j*i);
}
printf(”\n");
}
}
例子:
//0-10中偶数求和
void test(){
int sum=0;
for(int i=0;i<=10;i++){
if(i%2!=0){
continue;
}
sum=sum+i;
}
printf(“sum=%d”,sum);//sum=30
//cout<<sum<<endl;//30
}
七.函数
1.函数定义
2.参数传递
3.return语句
4.函数声明
5.局部对象
6.内联函数
6.1内联函数关键字:inline
例子:
inline void fun(){
cout<<“hello”<<endl;
}
6.2区别
普通函数:
main()函数《1》–>调用fun()函数《2》–>进入fun()函数头《3》–>执行fun()函数代码块《4》–>fun()函数结果《5》–>结束
内联函数:
编译时将函数体代码和实参代替函数调用语句,没有《2》《4》
适合简单函数,不适合复杂函数。
6.3类内定义:函数定义在类的内部。
类内定义的成员函数编译器会优先编译为内联函数。
6.4类外定义:成员函数的函数写在类的外面。
分类:同文件类外定义,分文件类外定义(一般选择这种)
自定义类型中讲到的例子就是分文件类外定义。
同文件类外定义例子:
#include
#include
using namespace std;
class Teacher{
public:
void setName(string _name);
string getName();
void setGender(string _gender);
string getGender();
void setAge(int _age);
int getAge();
void teach();
private:
string m_strName;
string m_strGender;
int m_iAge;
};
//类外定义:类名::方法名
void Teacher::setName(string _name){
m_strName=_name;
}
string Teacher::getName(){
return m_strName;
}
void Teacher::setGender(string _gender){
m_strGender=_gender;
}
string Teacher::getGender(){
return m_strGender;
}
void Teacher::setAge(int _age){
m_iAge=_age;
}
int Teacher::getAge(){
return m_iAge;
}
void Teacher::teach(){
cout<<“上课”<<endl;
}
int main(void){
Teacher t;
t.setName(“李四”);
t.setGender(“男”);
t.setAge(31);
cout<<t.getName()<<""<<t.getAge()<<endl;
t.teach();
system(“pause”);
return 0;
}
7.类成员函数
8.函数重载
方法名相同,形参列表不同。
构造函数的重载:
class Student(){
public:
//构造函数的重载
Student(){
m_strName=“Tom”;
}
Student(String name){
m_strName=name;//实例化的时候传值
}
private:
string m_strName;
};
八.其视频学习
OOP三大特性:继承封装多态
类是抽象的概念,对象是具体的事物,
类组成:数据成员和成员函数;
数据成员包括:普通数据成员+静态数据成员+对象成员+const+string
成员函数:属性封装函数+一般功能函数+特殊函数(构造函数+析构函数)
构造函数:拷贝构造函数+默认构造函数
类的使用:对象实例化
1.封装
隐概念:藏对象属性和实现细节,仅仅对外公开接口,
1.1访问限定符:
public private protected
1.2对象实例化
从栈实例化;从堆实例化
class TV{
public:
char name[20];
int type;
void changVol();
void power();
};
//从栈实例化对象
int main(void)
{
TV tv;//定义一个对象
TV tv[20];//定义一个对象数组,系统自动回收栈中内存
return 0;
}
//从堆实例化对象
int main(void){
TV *p=new TV();//指针指向一块内存,使用new 创建的,在堆中,手动释放
TV *q=new TV[20];//
delete p;
delete []q;
return 0;
}
1.3对象成员的访问
不同的实例化方法对应不同的访问方法
class TV{
public:
char name[20];
int type;
void changVol();
void power();
};
//从栈实例化对象
int main(void)
{
TV tv;//定义一个对象
tv.type=0;//对象访问成员的方式是点
tv.changeVol();
return 0;
}
//从堆实例化对象
int main(void){
TV *p=new TV();
if(p==NULL){
//内存地址p是NULL,说明申请失败
Return 0;
}
p->type=0;
p->changeVol();
delete p;//释放内存
p=NULL;
return 0;
}
1.4数据的封装
get set方法
例子:
#include
#include
#include<stdlib.h>
using namespace std;
class Student{
public:
//这就是类内定义,按照inline执行
void setId(int id){
m_iId=id;
}
int getId(){
return m_iId;
}
void setName(string name){
m_strName=name;
}
string getName(){
return m_strName;
}
private:
//这里面定义的是数据成员
int m_iId;
string m_strName;
};
int main(void){
Student std;
std.setId(001);
std.setName(“Tom”);
cout<<std.getId()<<endl;
cout<<std.getName()<<endl;
system("pause");
return 0;
}
2.对象结构
2.1内存分区:
栈区:int x=0; int *p=NULL;//内存由系统控制
堆区:int *p=new int[20];//new出来的需要自己delete
全局区:存储全局变量及静态变量
常量区:string str=“hello”;
代码区:存储逻辑代码的二进制
2.2对象初始化:
分类:有且仅有一次的初始化;根据条件初始化;
2.3构造函数:
在对象实例化的时候被自动调用;仅被调用一次
构造函数与类名同名,没有返回值,可以有多个重载形式,
即使有多个构造函数,但是实例化时仅有一个;
当用户没有定义构造函数的时候,编译器自动生成一个构造函数;
默认构造函数:实例化对象时不需要传递参数;
但是一个类可以没有默认构造函数。
2.4 构造函数初始化列表
例子:
class Student{
public:
//初始化列表这样
Student():m_strName(“Tim”),m_iAge(10){}
private:
string m_strName;
int m_iAge;
};
初始化列表先于构造函数执行;
初始化列表只能用于构造函数;
初始化列表可以同时初始化多个数据成员;
说明初始化空列表的必要性例子:
class Circle{
public:
//Circle(){m_dpi=3.14}//这样会报错,const是常量
Circle():m_dpi(3.14){}//这样可以编译通过
private:
const double m_dpi;
};
2.5 拷贝构造函数
构造函数:
无参构造函数:默认构造函数;
有参构造函数:参数带默认值,参数无默认值;
系统自动生成的函数:
普通构造函数和拷贝构造函数
定义格式:类名(const 类名& 变量名)
拷贝构造函数不可以重载,因为参数是确定的;
当没有自定义的拷贝构造函数时,系统自动生成一个拷贝构造函数;
#include
#include
using namespace std;
class Student{
public:
Student(){
cout<<“Student”<<endl;
}
};
int main(void){
Student stu1;//只打印一行 Student
Student stu2=stu1;//这一行没执行?
Student stu3(stu1);
system("pause");
return 0;
}
拷贝构造函数
定义格式:类名(const 类名& 变量名)
#include
#include
using namespace std;
class Student{
public:
Student(){
m_strName=“Tim”;
cout<<“one”<<endl;
}
Student(const Student& stu){
cout<<“two”<<endl;
}
private:
string m_strName;
};
int main(void){
Student stu1;//one
Student stu2=stu1;//two 说明调用的是拷贝构造函数
Student stu3(stu1);//two
system(“pause”);
return 0;
}
2.6 析构函数
任务:完成系统资源的归还。
定义格式:~类名()
如果没有自定义的析构函数,则系统自动生成;
析构函数在对象销毁时自动调用;
没有返回值,没有参数也不能重载。
例子说明:
第一个Teacher.h文件中:
#include
#include
using namespace std;
class Teacher{
public:
Teacher(string name=“Jim”,int age=12);
Teacher(const Teacher& tae);
~Teacher();//定义析构函数
void setName(string name);
string getName();
void setAge(int age);
int getAge();
private:
string m_strName;
int m_iAge;
};
第二个Teacher.cpp文件中:
#include “Teacher.h”
using namespace std;
Teacher::Teacher(string name,int age):m_strName(name),m_iAge(age)
{
//普通构造函数
cout<<“Teacher(string name,int age)”<<endl;
}
Teacher::Teacher(const Teacher& tea)
{
cout<<“拷贝构造函数”<<endl;
}
Teacher::~Teacher(){
cout<<“析构函数”<<endl;
}
void Teacher::setName(string name){
m_strName=name;
}
string Teacher::getName(){
return m_strName;
}
void Teacher::setAge(int age){
m_iAge=age;
}
int Teacher::getAge(){
return m_iAge;
}
第三个one.cpp文件中:
#include
#include<stdlib.h>
#include
#include “Teacher.h”
using namespace std;
//定义格式:类名(const 类名& 变量名)
void test(Teacher t1){
}
int main(void){
/*
Teacher t;//Teacher(string name,int age)
test(t);//拷贝构造函数
/
/ 使用堆初始化
Teacher *p=new Teacher();//Teacher(string name,int age)
delete p;//析构函数
*/
Teacher t;//Teacher(string name,int age)
Teacher t2(t);//拷贝构造函数
system(“pause”);
return 0;
}