一、类和对象的介绍
先从需求入手,从问题中抽离出来里面有哪些类别
例子:游戏中:角色,武器等都是类。图书管理系统中:图书,管理员,读者等都是类
对象:类里面具体的某一个事物,比如图书中的C语言,游戏角色中的关羽,游戏武器中的刀枪棍棒等都是对象
类;从一些相似的事物中抽离出来一些相同的属性(数据)和行为(函数),抽象成一个类。
对象:从特定的类别中创造出一个具体的事物。
1.C++面向对象解决问题的思路
1.设计类 2.创建对象 3.使用对象去解决问题
2.C++里面的四大特征
1、抽象:从一些相似的事物中抽离出来一些相同的属性(数据)和行为(函数),抽象成一个类
2、封装:加了权限 --- 基于安全考虑
3、继承:从一个类里面继承另外一个类的一些属性或者行为 动物:年龄、叫 狗,猫
4、多态:不同事物对统一行为的不同表现,比如:打怪兽,怪兽打死、怪兽反杀、掉血
二、类设计
一定要抽离出来属性和行为。
1.类定义
格式:
class 类名
{
private:
私有的成员变量和成员函数
protected:
保护的成员变量和成员函数
public:
公告的成员变量和成员函数
};
例子:猫类拥有很多种类,各种体型,各种毛色,以及不同的年龄,会叫,会吃东西
其中种类,体型,毛色,年龄这些都可以称之为属性,而叫,吃东西这种则是行为。
class Cat
{
private:
string brand;
string size;
string color;
int age;
public:
void bark(void)
{
cout << "喵喵喵" << endl;
}
};
当需要定义一个数据类型为猫类的变量时:Cat c; 使用类中的函数就为:c.bark();
2.权限
public:所有的成员属性和成员函数可以在类内访问,也可以在外部通过创建对象进行调用
private:所有的成员属性和成员函数可以在类内访问,不能再外部访问,一般设计接口函数set,get函数
protected:所有的成员属性和成员函数可以在类内访问,也可以在他的子类中访问
一般设计类的时候属性设计成私有的-private,函数设计成共有的-public。
三、成员函数
1.成员函数介绍
分类:普通成员函数、构造函数、析构函数、复制构造函数
定义位置:
类内定义:默认是内联函数
类外定义:类内声明,类外定义(推荐) 类外声明:函数名前要加 类名::
2.this指针
成员函数内部有一个this指针。谁调用成员函数,this指针就指向谁。
类里面所有的对象都是独立的属性成员,成员函数时共有的。
this指针是类成员函数内部隐式 存在的。
如果数据成员的名称和参数的名字重复了,就需要显式使用this指针赋值。(如果先避免,尽量保证数据成员的名称和参数的名称不同)
void Point::setX(int xp)
{
// this->xp = xp; // 指针形式
// this指针指向了调用它的对象 ,this指针保存了对象的地址
// *this --- 调用的对象
(*this).xp = xp; // 对象形式
}
3.特殊函数之普通构造函数
作用:构造函数实在创建对像的时候自动调用,一般完成对象的赋值或者初始化操作。
分类:普通构造函数 复制构造函数
普通构造函数
类名(形参)
{
}
注意:构造函数的名称一定摇和类名一致
不写返回值类型
创建对象的时候自动调用,不能手动调用
构造函数卸载public权限里面
构造函数可以是多个,支持函数重载
构造函数如果自定义就用定义的构造函数,如果没有定义就使用系统默认
构造函数支持 形参默认值,但是形参默认是和函数重载在一起的时候要小心冲突
构造函数卸载类外部,有默认参数的时候,默认参数只能有一个位置,定义或者声明,尽量将默认参数卸载类内部的函数声明的位置
4.特殊构造函数之析构函数
析构函数:对象销毁的时候自动调用的函数,一般用来清楚数据成员的空间。
格式:
~类名()
{
}
注意:
析构函数只能有一个
使用对象超出其作用域,自动调用对应的类的析构函数
析构函数是用来清理空间(有堆区空间,则需要清理堆区空间)(不是释放成员空间)
为了安全,防止存在隐患---防止内存泄漏
函数名与类名相同,并且前面加上~
没有返回值类型,没有形参
析构函数可以显式调用,通常不显式调用 --- 不推荐
析构函数如果自定义就使用定义的析构,如果没有提供那就调用系统提供的析构函数
#include<iostream>
using namespace std;
class Point
{
private:
int xp;
int yp;
int *zp;
public:
// 创造对象的时候自动调用
Point(int x,int y)
{
xp = x;
yp = y;
zp = new int;
cout << "调用有参构造函数" << endl;
}
// 对象销毁的自动调用,析构函数
~Point()
{
if(zp != NULL)
{
delete zp;
zp = NULL;
cout << "析构函数" << endl;
}
}
};
int main()
{
Point a(1,3);
a.~Point();
return 0;
}
5.特殊函数之复制构造函数
作用:对象复制
默认构造函数,可以实现将一个对象中的数值一对一的复制到另一个空间里面去
#include<iostream>
using namespace std;
class Point
{
public:
int xp;
int yp;
Point(int x,int y)
{
xp = x;
yp = y;
}
void show(void)
{
cout << "xp:" << xp << ",yp:" << yp << endl;
}
};
int main()
{
Point a(1,3);
Point b = a;
a.show();
b.show();
return 0;
}
但是如果数据成员里面有指针,那就会造成多个对象的成员指向同一片空间,就可能造成误操作。解决办法:自定义复制构造函数
例子:
#include<iostream>
using namespace std;
class Point
{
public:
int xp;
int yp;
int *zp;
Point(int x,int y)
{
xp = x;
yp = y;
}
void show(void)
{
cout << "xp:" << xp << ",yp:" << yp << ",*zp" << *zp << endl;
}
};
int main()
{
Point a(1,3);
*(a.zp) = 10;
Point b = a;
*(b.zp) = 100;
a.show();
b.show();
return 0;
}
复制构造函数格式:
类名(const 类名 &形参名)
{
//自己实现对成员数据的一一复制
}
注意:
一个类里面复制构造函数只能有一个
和类同名,有一个参数,一般是常量引用对象
一般复制构造不写,使用默认的,但是如果成员有指针或者堆区空间就要自定义
普通构造函数和复制构造函数只会执行一个,具体看参数
例子:普通构造函数和复制构造函数
#include<iostream>
using namespace std;
class Point
{
public:
int xp;
int yp;
int *zp;
Point(int x,int y)
{
xp = x;
yp = y;
cout << "普通构造函数" << endl;
}
Point(const Point& p1)
{
xp = p1.xp;
yp = p1.yp;
zp = new int;
// 拷贝堆区的值
*zp = *(p1.zp);
cout << "复制构造函数" << endl;
}
void show(void)
{
cout << "xp:" << xp << ",yp:" << yp << ",*zp" << *zp << endl;
}
};
int main()
{
Point a(1,3); // 普通构造函数
Point b(a); // 复制构造函数
return 0;
}
6.数据成员的初始化
1.初始化表达式(非静态成员)
类名(形参):成员名(参数名),成员名(参数名)
{
}
注意:
初始化表达式放在构造函数
如果成员里面有const成员那么只能通过初始化的形式赋值
如果构造函数重载了,在所有的构造函数后面都要设置初始化表达式
例子:
#include<iostream>
using namespace std;
class Point
{
public:
int xp;
int yp;
const int zp;
Point(int x,int y,int z):xp(x),yp(y),zp(z)
{
}
Point(int z):zp(z)
{
xp = 5;
yp = 10;
}
void show(void)
{
cout << "xp:" << xp << ",yp:" << yp << ",zp" << zp << endl;
}
};
int main()
{
Point a(1,3,5);
a.show();
Point b(5);
b.show();
return 0;
}
**************************************************************************************************************
总结:
类和对象:
类:类别,属性和行为
对象:由类创造,对象自动拥有类中的属性和行为
C++解决问题
1、设计类
2、创建对象
3、使用对象解决问题
C++面向对象有4大特性
抽象
封装
继承
多态
---------------------------------------------------------------------------
类的定义
class 类名
{
private:
私有成员(数据和函数)
protected:
保护成员(数据和函数)
public:
公共成员(数据和函数)
};
权限:
public:公共,属性和函数在类外(创建对象)和类内
private:私有,只能在类内,类外访问设置接口函数
protected:保护,只有在类内或者子类中可以访问
注意:
成员默认是私有的 -- private
权限的书写形式没有顺序之分。
----------------------------------------------------------------------------
成员函数
分类:普通成员函数和特殊成员函数 (构造、赋值构造、析构)
定义位置:
类内:定义成员函数 (声明和定义在一起)
类外:类内声明,类外定义
类外定义:在函数名的前面 + 类名::
this指针
this指针存在于成员函数中,谁调用这个成员函数,this就指向谁。
如果函数的形参名称和数据成员重名,必须显示使用。
this --- 指向调用的成员
*this --- 就是调用对象
------------------------------------------------------------------------------
特殊函数的构造函数
构造函数:创建对象的时候自动调用,一般完成 对象数据成员内的赋值或者初始化
分类:普通构造函数 复制构造函数
普通构造函数
类名(形参)
{
}
注意:构造函数的名称一定要和类名一致
不写返回值类型
创建对象的时候自动调用,不能手动调用
构造函数写在public权限里面。
构造函数可以有多个,支持函数重载
构造函数如果自定义就用定义的构造函数,如果没有定义就使用系统默认。
构造函数支持 形参默认值,但是形参默认是和函数重载在一起的时候小心冲突。
构造函数写在类外部,有默认参数的时候,默认参数只能有一个位置,定义或者声明,尽量将默认参数写在类内部的函数声明的位置。
------------------------------------------------------------------------------
特殊函数的析构函数
析构函数:对象销毁的时候自动调用,用来销毁动态申请的空间
析构函数格式:
~类名()
{
}
注意:
1、析构函数只能有一个
2、使用对象超出其作用域 ,自动调用对应的类的析构函数
3、析构函数是用来清理空间(有堆区空间,则需要清理堆区空间)(不是释放成员空间)
4、为了安全,防止存在隐患---防止内存泄漏
5、函数名与类名相同,并且前面加上~
6、没有返回值类型,没有形参
7、析构函数可以显式调用,通常不显式调用 -- 不推荐 -- 防止堆区空间重复释放
8、析构如果自定义就使用定义的析构,如果没有提供那就调用系统提供的析构函数
----------------------------------------------------------------------------------------
特殊函数的复制构造函数
赋值构造函数:如果数据成员有指针,默认拷贝就会造成不同对象的成员指向同一块空间,造成问题
自定义复制构造函数:
类名(const 类名 & 形参)
{
}
注意事项:
只能有一个
函数名和类名同名,有一个形参是常量引用对象
一般复制构造不写,使用默认的,但是如果成员有指针或者堆区空间就要自定义
普通构造函数和复制构造函数只会执行一个,具体看参数怎么
-----------------------------------------------------------------------------
数据成员初始化
初始化表达式
类名(形参列表):成员名(形参名),成员名(形参名)
{
}
注意:初始化表达式放在构造函数
如果成员里面有const成员那么只能通过初始化的形式赋值
如果构造函数重载了,在所有的构造函数后面都要设置初始化表达式
----------------------------------------------------------------------------------------------
成员函数:
普通成员
特殊的成员函数:构造 析构 复制构造函数