- 面向对象
概念:基于对象概念,以对象为中心,以类和继承为构造机制,来认识,理解,和刻画客观世界和设计构建相应的软件系统(模拟现实)
1、对象是由数据允许的操作组成的封装体,与客观事实有直接的对应关系
2、面向对象不是某种语言特性,而是一种编程思想
例:“今天我请人类吃饭”这种表达有点不正常的。“今天我请芸芸吃饭”这很正常。故称为面向对象
- 抽象和类
抽象:从具体事务抽取共同的本质特征(例如人是由细胞组成,但是这样思考的话太复杂了,就看成整体就行,男人、女人)这种由复杂到简答来描述的过程就是抽象,即实体、属性集合、物种集合
类:1)类是一种将抽象转化为用户定义类型的工具(类如画家是用画板去画画,类就是代码,将抽象转换过来)。2)将数据表示和操纵数据的方法组合成一个整体。3)类的实例称为对象(实例就是调用类的方法,用类中方法(函数)去解决问题,这种封装好的方法就是实例化)。4)类中的属性(变量)、方法(函数)成为成员。(类就是属性+方法)。5)类的实例称为对象,对象的集合称为类
- 概念理解了,下面说一下格式
注意:
1、class声明类型与struct声明类型 仅仅在形式上不同而已
2、唯一的区别在于与struct声明类型默认成员是私有的(private),而struct的默认类型是公有的(public)
*私有的必要性:女朋友,牙刷,手机等等私有物品
//类的声明
使用class/struct关键字声明类型
class 类名{}; //class Landowner{};
struct 类名{}; //struct Hero{};
//修饰符
//修饰成员:将修饰关键字放置在类定义的大括号中添加冒号
//属性解释
public //修饰的成员在任何地方都可以访问
private //修饰的成员只能在类中或者友元函数中可以访问
protected //修饰的成员可以在类中函数、子类函数、及友元函数中访问
修饰符下的属性变量可以通过方法(函数)判断的方法,进行封装,封装就是用函数封装,函数声明和函数定义都在
public
中进行.
private:
string gender; //也可以加下划线,不过加不加无所谓,共识是加上画线表示私有变量
public:
int age; //同样的方法进行封装,这里就不举例
//对属性封装不需要声明函数,直接定义函数对gender属性进行封装
void Set_gender(string input_gender)//定义函数(封装体)
{
if(input_gender != "male" && input_gender != "female")
{
gender = "保密";
}
else
{
gender = input_gender;
}
}
//函数定义(方法)
格式和普通的函数一样,需要函数声明和函数定义,不同的是函数定义时要加上双冒号::作用域解析运算符
1、类的成员函数:函数声明(在头文件中)
class 类名{
修饰符:
成员列表;
函数声明;
};
例如:
class Landowner{
public:
string name;
void sum1(int, int);//在头文件定义类中声明函数,在cpp文件中定义函数
}
2、类的成员函数:函数定义(在cpp文件中)
返回值类型 类名::函数名(){}
例如
void Landowner::sum1(int num1, int num2)//加上作用域解析符
{
int result = num1 + num2;
}
- 构造函数与析构函数
形象说法:对象在出生时调用构造函数,在回收时调用析构函数
//举个栗子
//头文件中
class Students
{
public:
Students(string,string);//构造函数的声明
~Students();//析构函数,总是成双成对的出现
void showinfo();//声明函数
private:
_name = name;
_desc = desc;
};
//在cpp文件中
//传参方式1
Student::Students(string name, string desc)//构造函数定义
{
_name = name;
_desc = desc;
}
/*
//传参方式2
Student::Students(string name, string desc):_name(name),_desc(desc);
//传参还可以赋默认值,设置默认值,外部的输入无效,打印的是默认值
Student::Students(string name, string desc):_name(name),_desc("666");
*/
void Students::showinfo()//显示信息函数
{
cout << "name: " << name << endl;
cou << "describe" << desc << endl;
}
//在主文件中main.cpp
Students stu1(别名) = Students("大卫", "帅气") ;
stu1.showinfo(); //非指针调用直接用点
Students* stu2 = new Students("贝尔", "牛逼的");
stu2->showinfo(); //指针调用用的箭头
//析构函数会自动调去释放栈内存的变量
delete stu2;//堆内存的变量需要手动删除释放
//上代码
main.cpp
#include <iostream>
#include "Students.h"
using namespace std;
int main()
{
//构造函数的重载规则跟普通函数的重载规则相同,重载的时候不关注的他的返回值,只关注返回类型
Students stu1;//在栈内存中直接实例化
Students stu2("马化腾","真有钱");//
Students stu3(20);
Students stu4("马云", "真有钱");
// Students stu5 = 100;
//Students stu6 = "牛逼轰轰轰";//这里会进行报错,说不匹配int类型,不能同时匹配int和string
stu2.showinfo();
//另外一种调用方式是通过指针的方式调用对象
Students* stu7 = new Students("杰克马","真牛逼!!"); //创建一个指针,指向这个类,调用这个方法
stu7->showinfo();//对于指针类型访问属性方法用->实现
delete stu7;
return 0;
}
Students.h
#ifndef STUDENTS_H
#define STUDENTS_H
#include <iostream>
using namespace std;
class Students
{
public:
//多个构造函数重名的原因是支持构造函数重载
Students();//默认构造函数,通过构造函数的方法需要用双冒号指明作用域解析运算符
Students(int );//自定义构造函数,并指明参数类型年龄
Students(string);//这样会报错,会导致不匹配第一个int型,即构造函数若指定一个参数类型时,不支持再指定一个参数不同类型
Students(string, string);//自定义带参构造
~Students();//析构函数
void showinfo();
string Getname()
{
return _name;
}
void Setname(string val)
{
_name = val;
}
string Getdesc() {
return _desc;
}
void Setdesc(string val) {
_desc = val;
}
int Getage() {
return _age;
}
void Setage(int val)
{
if(val < 0)
{
_age = 18;
}
else
{
_age = val;
}
}
protected:
private:
string _name;
string _desc;
int _age;
};
#endif // STUDENTS_H
Students.hpp
/*
*创建时间:
*描 述:
*作 者:
*/
#include <iostream>
using namespace std;
#include "Students.h"
Students::Students()//默认的初始化参数
{
cout << "这个是默认的构造" << endl;
}
Students::~Students()//析构函数负责释放内存空间
{
cout << _name << "被释放啦" << endl;
}
//自定义初始化参数
Students::Students(string name, string desc)//:_name(name),_desc(desc)//方法二:初始化参数列表的写法,
{
_name = name;
_desc = desc;
cout << "这个是string name/desc构造" << endl;
}
Students::Students(int age)
{
Setage(age);
cout << "这个是int age构造" << endl;
}
Students::Students(string name)
{
cout << "这个是单个string构造" << endl;
}
void Students::showinfo()//在类里面进行性函数定义,要加上作用域解析运算符
{
cout << _name << _desc <<endl;
}
//程序输出
这个是默认的构造
这个是string name/desc构造
这个是int age构造
这个是string name/desc构造
马化腾真有钱
这个是string name/desc构造
杰克马真牛逼!!
杰克马被释放啦
马云被释放啦
被释放啦
马化腾被释放啦
被释放啦
Process returned 0 (0x0) execution time : 0.092 s
Press any key to continue.
构造函数小结:
1、语法:名字和类名相同,没有返回值
2、作用:处于初始化对象
3、构造函数也可以重载
4、默认构造很重要,没有默认构造,则无法构造数组
5、如果一个类没有构造函数、析构函数,则编译器隐含的生成为其添加一个
对于成员的初始化和析构:
1、当对象被构造时,成员变量也被构造(成员函数的构造函数被调用)
2、当对象被析构时,成员变量也被析构(成员函数的析构函数被调用)
- democlass.cpp
/*
*创建时间:
*描 述:
*作 者:阿代
*/
#include <iostream>
using namespace std;
class Other
{
public:
Other()//默认构造
{
cout << "Other被创建 " << endl;
}
~Other()//默认析构
{
cout << "Other被析构 " << endl;
}
};
class Child
{
public:
Child()//默认构造
{
cout << "Child被创建 " << endl;
}
~Child()//默认析构
{
cout << "Child被析构 " << endl;
}
};
class Object
{
public:
Object()//默认构造
{
cout << "Object被创建 " << endl;
}
~Object()//默认析构
{
cout << "Object被析构 " << endl;
}
private:
Child m_child;//这里Child是一个类,作为Object的成员变量
Other m_other;
};
- main.cpp
#include <iostream>
using namespace std;
#include "democlass.cpp"
int main()
{
{//代码块表示出了块生命周期就结束
Object obj;
}
return 0;
}
//程序输出
Child被创建
Other被创建
Object被创建
Object被析构
Other被析构
Child被析构
Process returned 0 (0x0) execution time : 0.113 s
Press any key to continue.
可以很明显的看出,对像对成员变量构造的顺序:成员变量先被构造,对象后被构造,在析构顺序上刚好和构造函数相反
对于两个成员函数,则是按照先后顺序进行的构造