C++
c 面向过程
c++ 面向对象
后缀名:.cpp
编译:g++
名空间 命名空间管理
using namespace std; //指定默认的名空间 :: //欲解析运算符,指定名空间的函数 C语言头文件:<stdio.h> <string.h> C++头文件:<iostream> <cstring> //兼容性强,可以包含除自己本身的C语言的头文件
一、数据的输入与输出
1.cin (输入) – 默认与键盘链接,接受从键盘输入的数据信息。
语法:cin >> 变量;
2.cout(输出) – 默认与屏幕链接,将数据显示到屏幕上。
语法: cout << 变量;
#include <iostream>
using namespace std;
#include<string>
int main()
{
//整型的输入输出
int num ;
cout << "请给整型int赋值:" << endl;
cin >> num;
cout << "整型int = " << num << endl;
//浮点型的输入输出
double d ;
cout << "请给浮点型 double 赋值:" << endl;
cin >> d;
cout << "浮点型 double = " <<d<< endl;
//字符型的输入输出
char ch ;
cout << "请给字符型 char 赋值:" << endl;
cin >> ch;
cout << "字符型 char = " << ch << endl;
//字符串的输入输出
string str;
cout << "请给字符串赋值:" << endl;
cin >> str;
cout << "ans = " << str << endl;
//布尔型输入输出
bool flag;
cout << "请给布尔型bool赋值:" << endl;
cin >> flag; //输入0为0 其余任何非0数都是1。
cout << "布尔型 bool = " << flag << endl;
//实例 输入-520 显示-我爱C++!
int num1;
string str1 = "我爱C++!";
cout << "请输入 520 :" << endl;
cin >> num1;
cout << str1 << endl;
system("pause");
return 0;
}
二、类和对象
封装:基础 类的抽象过程 描述一类事物的特点
继承:核心 在原有的特点/功能上加上新的特点/功能
多态:延伸 特点:同一条命令作用在不同对象身上显示效果不同
2.1 封装
类:一类事物的统称
对象:某类事物的一个特例/个体
例如:
人可以作为对象,属性有姓名、年龄、身高、体重…,行为有走、跑、跳、吃饭、唱歌…
车也可以作为对象,属性有轮胎、方向盘、车灯…,行为有载人、放音乐、放空调…
具有相同性质的对象,我们可以抽象称为类,人属于人类,车属于车类
如何描述一类事物:数据成员(变量)+ 成员方法(函数,宏,inline内联函数[带参宏])
实例化对象:
int i;//实例化整型对象i
A a1; //实例化A类型的对象a1
封装的意义:
- 将属性和行为作为一个整体,表现生活中的事物
- 将属性和行为加以权限控制
封装意义一:
在设计类的时候,属性和行为写在一起,表现事物
封装意义二:
类在设计时,可以把属性和行为放在不同的权限下,加以控制
访问权限有三种:
访问权限有三种:
公共权限 public 类内可以访问 类外可以访问
保护权限 protected 类内可以访问 类外不可以访问
私有权限 private 类内可以访问 类外不可以访问
struct和class区别
在C++中 struct和class唯一的区别就在于 默认的访问权限不同
区别:
- struct 默认权限为公共
- class 默认权限为私有
代码演示:
#include <iostream>
using namespace std;
//内联函数inline 1类内实现 2用inline关键字类内声明,实现可以写在类外
//public protected private
class Clock
{
public:
void ShowTime();
void SetTime(int h,int m,int s);
private:
int hour;
int minute;
int second;
};
void Clock::ShowTime() //::欲解析运算符,指定名空间的函数
{ cout << hour << ":" << minute << ":" << second << endl; }
void Clock::SetTime(int h,int m,int s)//::欲解析运算符,指定名空间的函数
{ hour = h; minute = m; second = s; }
int main()
{
Clock c1;
c1.ShowTime();
return 0;
}
对类进行sizeof,得到的是数据成员的大小,不包括成员方法大小
this指针:this指针指向被调用的成员函数所属的对象
this指针是隐含每一个非静态成员函数内的一种指针
this指针不需要定义,直接使用即可
this指针的用途:
- 当形参和成员变量同名时,可用this指针来区分
- 在类的非静态成员函数中返回对象本身,可使用return *this
2.2 构造函数
作用:初始化,在一个对象生成的时候被隐式调用,默认有一个系统生成的构造函数,若我们自行实现了构造函数,系统默认的那个不再生成
长相:函数名与类名同名,不需要返回值,可传参,可不传参
构造函数语法 :类名(){}
- 构造函数,没有返回值也不写void
- 函数名称与类名相同
- 构造函数可以有参数,因此可以发生重载
- 程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次
代码演示:
#include <iostream>
using namespace std;
/*类中的特殊函数*/
/*
构造函数:作用:初始化,在一个对象生成的时候被隐式调用
默认有一个系统生成的构造函数,若我们自行实现了构造函数,系统默认的那个不再生成
长相:函数名与类同名,不需要返回值,可传参(可1个或多个)可无参
构造函数可以同时存在多个
*/
class Clock
{
public:
Clock(int h=0,int m=0,int s=0);
void ShowTime();
void SetTime(int h,int m,int s);
private:
int hour;
int minute;
int second;
};
Clock::Clock(int h,int m,int s)
{
cout << "Clock(3*int)" << endl;
hour = h ;
minute = m;
second = s;
}
void Clock::ShowTime()
{ cout << hour << ":" << minute << ":" << second << endl; }
void Clock::SetTime(int h,int m,int s)
{ hour = h; minute = m; second = s; }
int main()
{
Clock c0;
Clock c1(4);
Clock c2(14,15);
// c1.ShowTime();
return 0;
}
2.3 拷贝构造函数
作用:初始化,在一个对象生成的时候,且用相同类型的已经存在的对象初始化时,调用拷贝构造函数,默认有一个系统生成的拷贝构造函数,若我们自行实现了拷贝构造函数,系统默认的那个不再生成
长相:函数名与类名同名,不需要返回值,参数为常引用(引用通常用来函数传参)
C++中拷贝构造函数调用时机通常有三种情况:
- 使用一个已经创建完毕的对象来初始化一个新对象
- 值传递的方式给函数参数传值
- 以值方式返回局部对象
代码演示:
#include <iostream>
using namespace std;
/*类中的特殊函数*/
/*
拷贝构造函数:作用:初始化 ,在一个对象生成时,且用相同类型的已存在的对象初始化时调用拷贝构造
默认有一个系统生成的拷贝构造函数,若我们自行实现了拷贝构造函数,系统默认的那个不再生成
长相:函数名与类同名,无返回值,参数为常引用
*/
class Clock
{
public:
Clock(int h=0,int m=0,int s=0);
Clock(const Clock &other);
~Clock();
void ShowTime();
void SetTime(int h,int m,int s);
private:
int hour;
int minute;
int second;
};
Clock::Clock(int h,int m,int s) //构造函数
{
cout << "Clock(3*int)" << endl;
hour = h ;
minute = m;
second = s;
}
Clock::Clock(const Clock &other) //拷贝构造函数
{
cout << "Clock(&)" << endl;
hour = other.hour;
minute = other.minute;
second = other.second;
}
Clock::~Clock() //析构函数
{
cout << "~Clock() " << hour << endl;
}
void Clock::ShowTime()
{ cout << hour << ":" << minute << ":" << second << endl; }
void Clock::SetTime(int h,int m,int s)
{ hour = h; minute = m; second = s; }
int main()
{
Clock c1(4);
Clock c2 = c1;
c2.ShowTime();
return 0;
}
2.4 析构函数
作用:清理或销毁,在一个对象生命周期即将终止的时候被隐式调用,默认有一个系统生成的析构函数,若我们自行实现了析构函数,系统默认的那个不再生成
长相:函数名与类名同名,前面加~,不需要返回值,不可传参
析构函数语法: ~类名(){}
- 析构函数,没有返回值也不写void
- 函数名称与类名相同,在名称前加上符号 ~
- 析构函数不可以有参数,因此不可以发生重载
- 程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次
代码演示:
#include <iostream>
using namespace std;
/*类中的特殊函数*/
/*
析构函数:作用:清理或销毁,在一个对象生命周期即将终止时被隐式调用
默认有一个系统生成的析构函数,若我们自行实现析构函数,系统默认的那个不再生成
长相:函数名与类同名,前面加~,不需要返回值,不可传参
*/
class Clock
{
public:
Clock(int h=0,int m=0,int s=0);
~Clock();
void ShowTime();
void SetTime(int h,int m,int s);
private:
int hour;
int minute;
int second;
};
Clock::Clock(int h,int m,int s)
{
cout << "Clock(3*int)" << endl;
hour = h ;
minute = m;
second = s;
}
Clock::~Clock()
{
cout << "~Clock() " << hour << endl;
}
void Clock::ShowTime()
{ cout << hour << ":" << minute << ":" << second << endl; }
void Clock::SetTime(int h,int m,int s)
{ hour = h; minute = m; second = s; }
int main()
{
Clock c0;
{
Clock c2(14,15);
}
Clock c1(4);
return 0;
}
对象的初始化和清理也是两个非常重要的安全问题
一个对象或者变量没有初始状态,对其使用后果是未知
同样的使用完一个对象或变量,没有及时清理,也会造成一定的安全问题
c++利用了构造函数和析构函数解决上述问题,这两个函数将会被编译器自动调用,完成对象初始化和清理工作。
对象的初始化和清理工作是编译器强制要我们做的事情,因此如果 我们不提供构造和析构,编译器会提供,编译器提供的构造函数和析构函数是空实现
2.2 继承
继承的好处:可以减少重复的代码
2.2.1 继承方式
继承的语法:class 子类 : 继承方式 父类
C++允许一个类继承多个类(多继承语法)
语法:class 子类 :继承方式 父类1 , 继承方式 父类2...
继承方式一共有三种:
- 公共继承
- 保护继承
- 私有继承
用法:class A : public B;
A 类称为子类 或 派生类
B 类称为父类 或 基类
继承的语法:class 子类 : 继承方式 父类
代码演示:
#include <iostream>
using namespace std;
/*
父类-子类 基类-派生类
parent->: public protected private
public: public protected -
protected: protected protected -
private: private private -
*/
class A
{
public:
A() {cout << "A()" << endl;}
~A() {cout << "~A()" << endl;}
void GetA() { cout << "A::GetA() " << a << endl;}
protected:
void Show() { cout << "A::Show()" << a << endl;}
private:
int a;
};
class B : public A
{
public:
B() {cout << "B()" << endl;}
~B() {cout << "~B()" << endl;}
void GetShow() { Show(); }
void GetA() { cout << "B::GetA() " << endl;}
};
int main()
{
B tmp;
tmp.GetA();
return 0;
}
问题:父类和子类的构造和析构顺序是谁先谁后?
子类继承父类后,当创建子类对象,也会调用父类的构造函数
总结:继承中 先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反
问题:当子类与父类出现同名的成员,如何通过子类对象,访问到子类或父类中同名的数据呢?
总结:
- 子类对象可以直接访问到子类中同名成员
- 子类对象加作用域可以访问到父类同名成员
- 当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数
三、动态内存申请
C:malloc free (不会调用构造和析构)
C++:new delete(会调用构造和析构)
1.1 new操作符
C++中利用new操作符在堆区开辟数据
堆区开辟的数据,由程序员手动开辟,手动释放,释放利用操作符 delete
语法:new 数据类型
利用new创建的数据,会返回该数据对应的类型的指针
示例1: 基本语法
#include <iostream>
using namespace std;
int main()
{
char *p = new char;
if(p == NULL)
return -1;
*p = 'a';
cout << *p << endl;
delete p;
return 0;
}
示例2:开辟数组
//堆区开辟数组
int main() {
int* arr = new int[10];
for (int i = 0; i < 10; i++)
{
arr[i] = i + 100;
}
for (int i = 0; i < 10; i++)
{
cout << arr[i] << endl;
}
//释放数组 delete 后加 []
delete[] arr;
system("pause");
return 0;
}
示例3
#include <iostream>
using namespace std;
class A
{
public:
A() { str = new char[1]; *str = '\0' };
~A() { delete []str; }
void Show() { cout << str << endl; }
private:
char *str;
};
int main()
{
A a1;
return 0;
}