目录
面向过程程序设计
对象:描述其属性的数据以及对这些数据施加的一组操作封装在一起构成的统一体。对象可认为是数据+操作。
类:类是具有相同的数据和相同的操作的一组对象的集合。
消息传递:对象之间的交互。
面向对象程序设计的基本特征:抽象、封装、继承、多态。
简单概括三大特性作用:
封装是为了代码模块化和增加安全性
继承是为了重用和扩展现有的代码模块
多态是为了接口复用
抽象:对具体对象(问题)进行概括,抽出这一类对象的公共性质并加以描述的过程。抽象的实现:通过类的声明。
封装:
保护数据成员,不让类以外的程序直接访问或者修改类的成员,只能通过其成员对应方法访问(即数据封装)
隐藏方法实现的具体细节,仅仅提供接口, 内容修改不影响外部调用(即方法封装)
继承:
三种继承方式:public、protected、private。
继承的目的: 重用代码,一个类B继承另一个类A,则B就继承了A中申明的成员以及函数
派生的目的: 代码扩展,继承自一个类然后添加自己的属性和方法则实现代码的扩展
缺陷:
父类变化了子类必须变化 增加了耦合性
多态:
接口的复用,一个接口多种实现
用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数
C++多态性是通过虚函数来实现的, 虚函数允许子类重新定义成员函数,而子类重新定义父类的做法称为覆盖或者重写
函数重载为允许多个不同名称的函数,这些函数函数列表不同或者函数个数不同或者两者都不同
编译时多态:主要指方法的重载 (在编译器编译期间就可以确定函数的调用地址,并产生代码,是静态的)
运行时多态:通过虚函数实现 (在运行时确定的调用地址)
#include <iostream> //编译预处理命令
using namespace std; //使用命名空间
int add(int a, int b); //函数原型说明
int main() //主函数
{
int x, y;
cout << "Enter two numbers: " << endl;//标准输入流cin
cin >> x;
cin >> y;
int sum = add(x, y);
cout << "The sum is : " << sum << '\n';//标准输出流cout
return 0;
}
int add(int a, int b) //定义add()函数,函数值为整型
{
return a + b;
}
结构名、联合名、枚举名都可直接作为类型名,在定义变量时,不用再在结构名、联合名、枚举名前面冠以struct、union、enum关键字
strcut Student
{
int age;
};
//C语言写法:struct Student stu;
//C++写法:Student stu;
//强制类型转换
C语言中要把整型数据转换成浮点型数据
int i=10;
float f=(float)i;
C++中可以把类型名作为函数名使用
int i=10;
float f=float(i);
在声明函数原型或函数定义时,为一个或多个参数指定缺省值
int func(int x=5,float y=2.3);
下面的调用都是正确的:
func(); //使用缺省值
func(10); //x使用实参值10,y使用缺省值2.3
func(3,4.5); // x和y分别使用实参值3,4.5
const修饰符
在C语言中,习惯使用#define
来定义常量,例如#define PI 3.14
,C++提供了一种更灵活、更安全的方式来定义常量,即使用const
修饰符来定义常量。例如const float PI = 3.14;
修饰指针所指向的变量,将该变量定义为常量
示例语句:const char *str=&c;
将指针本身修饰为常指针,指针所指向的变量仍为变量
示例语句: char *const str=&c;
指针本身修饰为常指针,指针所指向的变量修饰为常量
示例语句: const char *const str=&c;
函数重载
函数重载
同一个函数名对应不同的函数实现,每一类实现对应着一个函数体,名字相同,功能相同,只是参数的类型或参数的个数不同。
多个同名函数只是函数类型(函数返回值类型)不同时,它们不是重载函数
int add(int a,int b)
{
return a+b;
}
double add(double a,double b)
{
return a+b;
}
int add(int a,int b,int c)
{
return a+b+c;
}
内联函数
在函数名前冠以关键字inline
,该函数就被声明为内联函数。每当程序中出现对该函数的调用时,C++编译器使用函数体中的代码插入到调用该函数的语句之处,同时使用实参代替形参,以便在程序运行时不再进行函数调用。引入内联函数主要是为了消除调用函数时的系统开销,以提高运行速度。
说明:
- 内联函数在第一次被调用之前必须进行完整的定义,否则编译器将无法知道应该插入什么代码
- 在内联函数体内一般不能含有复杂的控制语句,如for语句和switch语句等
- 使用内联函数是一种空间换时间的措施,若内联函数较长,较复杂且调用较为频繁时不建议使用
构造函数
是一种特殊的成员函数,主要功能是为对象分配存储空间,以及为类成员变量赋初值
- 构造函数名必须与类名相同
- 没有任何返回值和返回类型
- 创建对象自动调用,不需要用户来调用,且只掉用一次
- 类没有定义任何构造函数,编译系统会自动为这个类生成一个默认的无参构造函数
构造函数定义
析构函数
是一种特殊的成员函数,当对象的生命周期结束时,用来释放分配给对象的内存空间爱你,并做一些清理的工作。
析构函数名与类名必须相同。
析构函数名前面必须加一个波浪号~。
没有参数,没有返回值,不能重载。
一个类中只能有一个析构函数。
没有定义析构函数,编译系统会自动为和这个类生成一个默认的析构函数。
析构函数的定义:
//1.类中定义 2.类中声明,类外定义
[类名::]~析构函数名()
{
函数体;
}
#include <iostream>
using namespace std;
class A {
public:
A() { cout << "A::A" << endl; }
~A() { cout << "A~A" << endl; }
void run(void) {
cout << "run()" << endl;
}
void run(int a) {
cout << "run(A)" << endl;
}
};
class B : public A {
public:
B() { cout << "B::B" << endl; }
~B() { cout << "B::~B" << endl; }
void run(int a) {
cout << "run(B)" << endl;
}
};
int main(void) {
B *b=new B;
delete b;
//b.run(0); //语句1
//b.A::run(1); //语句2
//b.A::run(); //语句4
return 0;
}
拷贝构造函数
拷贝构造函数是一个特殊的构造函数,其作用是用一个已经存在的对象初始化本类的新对象。可根据自己的需要定义拷贝构造函数,也可由系统生成一个缺省的拷贝构造函数。拷贝构造函数没有返回值。拷贝构造函数名与类名相同,但参数是本类对象的引用。
自定义拷贝构造函数
自定义拷贝构造函数的一般形式为:
类名(类名&对象名)
{
//拷贝构造函数的函数体
}
其中,对象名是用来初始化另一个对象的对象的引用。
this指针
每个成员函数都有一个特殊的指针this,它始终指向当前被调用的成员函数操作的对象
指针this是系统自动生成的、隐含于每个对象中的指针。当一个对象生成以后,系统就为这个对象定义了一个this指针,它指向这个对象的地址。也就是说,每一个成员函数都有一个this指针,当对象调用成员函数时,该成员函数的this指针便指向这个对象。这样,当不同的对象调用同一个成员函数时,编译器将根据该成员函数的this指针指向的对象确定引用哪个对象的成员函数。因此,成员函数访问数据成员的实际形式为:
this->成员变量
静态成员函数
以关键字static开头的成员为静态成员,多个类共享。
- static 成员变量属于类,不属于某个具体的对象
- 静态成员函数只能访问类中静态数据成员
静态数据成员
静态数据成员
//类内声明,类外定义
class xxx
{
static 数据类型 静态数据成员名;
}
数据类型 类名::静态数据成员名=初值
//访问
类名::静态数据成员名;
对象名.静态数据成员名;
对象指针名->静态数据成员名;
静态成员函数
在类定义中,前面有static说明的成员函数称为静态成员函数。静态成员函数属于整个类,是该类所有对象共享的成员函数,而不属于类中的某个对象。静态成员函数的作用不是为了对象之间的沟通,而是为了处理静态数据成员。定义静态成员函数的格式如下:
//类内声明,类外定义
class xxx
{