面向对象、运算符重载、继承和派生、this指针、析构函数、构造函数

什么是面向对象?
所谓面向对象就是基于对象概念,以对象为中心,以类和继承为构造机制,来认识、理解、刻画客观世界和设计、构建相应的软件系统(模拟现实)
1、对象是由数据和容许的操作组成的封装体,与客观实体有直接对应关系
2、面向对象不是某一种语言的特性,而是一种变编程思想
面向过程举例如: 开始游戏、洗牌、发牌、显示手牌、出牌、。。。
面向对象举例如:游戏参与者—行为模式是相同的玩家对象,相同的属性和行为
进行游戏的场景—牌桌对象负责显示游戏界面及内容
游戏规则系统-----裁判对象 负责判定牌面输赢等。
注意:
1、采用过程性编程方法时,首先要考虑遵循的步骤,然后考虑如何表示这些数据。
2、Oop程序员一般会考虑数据,不仅要考虑如何表示这些数据,还要考虑如何使用这些数据。
抽象和类
抽象 从具体事物抽取共同的本质特征
C++中的类
类是一种将抽象转换为用户定义类型的工具
将数据表示和操纵数据的方法组合成一个整体
类的实例称为对象
类中的变量和函数称为成员
地主类 成员变量:名称、积分、手牌、、、
成员函数: 摸牌、出牌、查看积分、、、

类的声明
使用class/struct关键字声明类型 class 类名{};
注意:
1、class方式声明的类型与struct声明的类型仅仅是形式上不同
2、其唯一的区别在于使用class声明的类型默认成员是私有的(private)struct声明的类型默认成员是公有的(public)
.hpp文件一般包含实现的内联函数 (内联函数相当于把整个代码复制一次)通常用于模板类这种声明与实现共存的情况
建议:只要不是纯模板,一律使用.h作为头文件后缀,使用.cpp文件作为函数的实现文件

常见访问修饰符:
Public:修饰的成员在任意地方都可以访问
Private:修饰的成员只能在类中或者友元函数中可以访问
Protected:修饰的成员可以在类中函数、子类函数以及友元函数中访问
修饰成员
将修饰关键字放置在类定义的大括号中,添加冒号
Class 类名{
修饰符:
成员列表;
};

函数声明
Class 类名{ class LandOwner{
修饰符1: public:
变量1类型 变量1名称; string name;
变量2类型 变量2 名称; long score;
修饰符2: public:
函数1返回类型 函数1名称(); void ShowScore();
} }
函数定义
返回类型 类名::函数名(){ void LandOwner::ShowScore(){
//函数操作 cout << score << endl;
} }

构造函数
以类名作为函数名 class LandOwner(
无返回值类型 private:
Int userld;
Public:
LandOwner()
{ userld = 10000;
}};
作用
初始化对象的数据成员
类对象被创建时,编译器为对象分配内存空间并自动调用构造函数以完成成员的初始化
构造函数的种类
无参构造
一般构造(重载构造)
拷贝构造
注意:
1、如果创建的类中未书写任何构造函数,系统会自动生成默认的无参构造函数(函数为空,什么都不做)也就是默认构造
2、如果书写了构造函数,系统就不会自动生成默认构造:如果希望自己有一个这样的无参构造函数,需要自己显示地书写出来
一般使用构造函数进行成员变量的初始化
带参构造
类名::构造(类型1 参数1,类型2 参数2,…){
//相关初始化代码
}
Student::Student(string name,string desc){
m _name = name;
m_desc = desc;
}
Student* stu = new Student(“撒贝宁”,”北大还行”);
Stu -> ShowInfo();
Student::Student(string name,string desc) : m_Name(name),m_desc(desc)//初始化参数列表
析构函数
对象过期时自动调用的特殊成员函数
析构函数一般用来完成清理工作
析构函数的名称是在类名前加上~
析构函数没有参数,只能有一个
注意:
1、析构函数用来释放对象使用的资源,并销毁对象的非static数据成员
2、无论何时一个对象被销毁,都会自动调用其析构函数(隐试析构)
使用类创建对象
第一种实例化方式
栈内存中创建:类似声明变量
自定义类型名 对象名[([参数列表])];
Student stu(); Student stu;
注意:1、stu对象由系统创建并释放,不用担心会出现内存泄漏
3、生命周期只在声明区域的大括号内
4、栈内存的优势是存取速度比较快(仅次于寄存器)缺点是存在栈中的数据大小与生命周期必须是确定的,缺乏灵活性

第二种实例化方式
在堆内存中创建:需要new关键字
Student* p_stu1 = new Student();
Student* p_stu2 = new Student();
auto* p_stu3 = new Student();
注意:
1、p_stu1是指针,必须使用delete释放
2、使用灵活(可以赋值给全局变量,可以把对象作为函数的返回值返回)
3、用好了功能强大,用不好很危险

This关键字
this指针
每个成员函数(包括构造和析构)都有一个this指针
this指针指向调用对象,即可以通过this关键字访问当前对象的成员
访问成员变量 访问成员函数
this ->成员名; this->函数名();
注意:
1、this指针的类型为类类型const(类名const),为右值
2、this指针本身不占用大小,它并不是对象的一部分,因此不会影响sizeof的结果
3、this的作用域在类成员函数的内部
4、this指针是类成员函数的第一个默认隐含参数,编译器自动维护传递,类编写不能显式传递
5、只有在类的非静态成员函数中才可以使用this指针,其他任何函数都不可以

运算符(operator)重载
运算符重载就是“想法转换”,它的目标是简化函数调用的方式
把标准的函数定义方式,重新定义为自己认为的方式
所谓重载,就是赋予新的含义
运算符重载也是一个道理 同一个运算符可以有不同的功能
1、运算符重载的语法格式: 返回类型 operator 被重载 的运算符(参数列表)
2、编译器实际调用 num3 = num1.operator+(num2);
定义一个运算符重载就像定义一个函数,只不过这个函数名称以operator关键字开头
+±-
Const int ptr1_num1 = &num1;
Int const ptr2_num1 = &num1;
Ptr1_num1 = &num2;//合法
ptr1_num1 = 1234;//不合法
const指向指针变量时:
1、如果只有一个const时,const位于
左侧 表示指针所指的数据是常量 不能通过该指针
修改实际数据 指针本身是变量可以指向其他内存单元
2、只有一个const时,如果const位于
右侧 表示指针本身是常量 不能指向其他内存单元,所指向的数据可以修改
Int * const ptr3_num1 = &num1;
3、如果有两个const位于
的左右两侧,表示指针和指针所指向的数据都不能修改
Const修饰函数参数

不能重载的运算符:.(点运算符) (成员指针访问运算符) ::(域运算符)
Sizeof(长度运算符) ?:(三元运算符/条件运算符)
重载不能修改运算变量的个数
比如,关系运算符是二元运算的,重载后也必须有两个变量参数运算
重载不能修改遇见符的优先级别
比如
和 /优先于 + 和 -,重载后这个优先级不会被修改
重载不能修改运算顺序
比如,赋值运算是从右到左的,重载后不能改变
友元函数
运算符声明成类成员还是声明独立友元函数建议准则:
C++规定,赋值运算符= 数组下标运算符[]、函数调用运算符()、成员访问运算符->在重载时必须声明为类的成员函数
流运算符 <<、>>类型转换运算符不能定义为类的成员函数,只能是友元函数
一元运算符和复合赋值运算符重载时,一般声明为类的成员函数
二元运算符在运算符重载时,一般声明为友元函数
注意:
1、对于很多运算符来说,可以选择使用成员函数或非成员函数来实现运算符重载,一般来说非成员函数应该是友元函数,这样才能直接访问类的私有数据
2、在定义运算符时,必须选择其中一种格式,而不能同时选择这两种格式,同时定义这两种格式将被视为二义性错误,导致编译错误
3、那么哪种格式最好呢?对于某些运算符来说,成员函数是唯一的合法的解释,在其他情况下,这两种格式没有太大的区别,有时根据类的设计,使用非成员函数版本可能更好(尤其为类定义类型转换时)
类型的自动转换和强制转换
在C++中,存在隐式类型转换语法(自动类型转换)
Int a = 12;
a = 22.5+a;
C++中提供显式类型转换语法(强制类型转换)
类型名(变量)
Int num = int(99.5);
C语言采用的语法格式
Int num = (int)99.5;
注意:
1、不管是自定义类型转换还是强制类型转换,前提是编译器必须知道如何转换如:
1)将浮点型数据赋值给整型变量时,舍弃其小数部分
2)将整型数据赋值给浮点型变量时,数值不变,但是以指数形式存储
3)将double型数据赋值给float型变量时,注意数值范围溢出
4)字符型数据都可以赋值给整型变量,此时存入的是字符的ASCII码
5)将一个int,short,或long型数据赋给一个char型变量,只将低8位原封不动的送到char型变量中
6)将有符号型数据赋值给长度相同的无符号型变量,连同原来的符号位一起传送
C++允许我们自定义类型转换规则
用户可以将其他类型转换为当前类类型,也可以将当前类类型转换为其他类型
这种自定义的类型转换规则只能以类的成员函数的形式出现
将其他类型转换为当前类类型需要借助转换构造函数
再谈构造函数
构造函数的作用:
构造函数的本意是在创建对象的时候初始化对象
编译器会根据传递的实参来匹配不同的(重载的)构造函数
构造函数的分类
//无参的默认构造,可以由编译器自动生成
Rectangle(); Rectangle rect1()
//用户定义的普通带参构造
Rectangle(float width,float height); Rectangle rect2(20,30)
//拷贝构造 在以拷贝方式初始化对象时调用
Rectangle(const Rectangle & rect); Rectangle rect3(rect2)
//转换构造 将其他类型转换为当前类型时调用
Rectangle(flaot width) Rectangle rect4(99.8) Rectangle rect5 = 66.6
类型转换函数
类型转换函数的作用就是将当前类类型转换为其他类型
它只能以成员函数的形式出现,也就是只能出现在类中
//类型转换函数的语法格式
Operator type(){
Return data;
}
类型转换函数的特点:
类型转换函数看起来没有返回值类型,其实是隐式地指明了返回值类型
类型转换函数也没有参数,因为要将当前类的对象转换为其他类型
实际上编译器会把当前对象的地址赋值给this指针,这样在函数体内就可以操作当前对象了
Operator float() const{ operator Circle(){
Return this ->width; return Circle(width *2);
} }
注意:
1、type可以是内置类型、类类型以及由typedef定义的类型别名,任何作为函数返回类型的类型(void)除外都是被支持的(不允许转换为数组或函数类型,可以转换为指针或引用类型)
2、类型转换函数一般不会更改被转换的对象,所以通常定义为const
3、类型转换函数可以被继承,可以是虚函数
什么是继承和派生?
C++中,代码重用是通过“继承(inheritance)”机制实现的
所谓“继承”就是在一个已经存在的类基础上,再建一个新类
从已有的类派生出新的类,派生类就继承了原有类(基类)的特征,包括成员和方法
通过继承可以完成下面的一些功能
可以在已有类的基础上增加新功能,如对于数组类,可以添加数学运算
可以给类添加数据成员,如对于字符串类,可以派生出一个类,并添加指定成员表示颜色
可以修改类方法的行为,如对于普通英雄类,可以派生出拥有更丰富技能的近战英雄类
注意:
继承机制只需提供同新特性,甚至不需要访问源码就可以派生出类

你可能感兴趣的:(面向对象、运算符重载、继承和派生、this指针、析构函数、构造函数)