C++ 面向对象编程1
概念
一切都可以是对象,一个程序可以由一组对象组成的一组整体,程序的功能就是通过对象之间传递消息来实现的。如上图所示,比如有一个人在家里,需要坐飞机到达某一个地方,那他需要经历的步骤可能为,走到公交站--》坐公交车到地铁站-》坐地铁到机场--》坐飞机到达目的地。
如果使用面向过程的编程方法就是将每一个步骤写成一个函数实现,按照顺序调用;
如果使用面向对象来实现上面的动作,则在实现动作之前需要将对象先创建出来,抽取当前情形下所感兴趣的特征,可以是变量或函数(功能),在当前情景下人需要走的功能,汽车和地铁需要载客的功能等,将这些功能组合起来便可以实现出当前情景下的动作。
如何描述对象类型
1.使用结构体(struct)描述
C++对结构体语法进行了扩展,结构体中既可以有成员变量,也可以有成员函数。因此结构体就可以用来描述对象的类型,在C++中,对象的类型叫类。可以看出其实C语言也可以实现,成员函数可以用函数指针来代替。
实验程序
实现一个时间类提供一个走秒的函数run(调用一次时间+1秒),在主函数中调用该函数实现时间的走动。
#include <iostream>
#include <unistd.h>
#include <iomanip>
using namespace std;
struct Time{ //创建类
int r_hours;
int r_minute;
int r_second;
//设置当前时间的函数
void set_time(int hours = 23, int minute = 59, int second = 55)
{
r_hours = hours;
r_minute = minute;
r_second = second;
}
//打印当前时间的函数
void show_time()
{
//setw(2)表示输出的字符宽度为2,不足的部分用字符'0'填充
cout<<setw(2)<<setfill('0')<<r_hours<<":"<<setw(2)<<setfill('0')<<r_minute<<":"<<setw(2)<<setfill('0')<<r_second<<endl;
}
//走秒的函数
void run_time()
{
r_second++;
if (r_second==60)
{
r_second = 0;
r_minute++;
if (r_minute==60)
{
r_minute = 0;
r_hours++;
if (r_hours==24)
{
r_hours = 0;
}
}
}
}
};
int main()
{
Time time;//创建一个对象
time.set_time();
while(1)
{
time.show_time();
sleep(1);
time.run_time();
}
}
输出结果:
2.使用class类来描述对象的类型
不过大部分情况下不会使用struct来实现面向对象的编程,而是使用class,其用法和struct几乎一样,只是类中的成员具有访问属性,访问属性分为三种:
访问属性 | public --- 公有属性 | protected --- 保护属性 | private --- 私有属性 |
---|---|---|---|
特点 | 可以在类的内部和外部访问 | 可以在类内和子类中访问 | 只能在类内访问 |
![]() |
|||
类成员的访问属性就是实现封装的基础,封装就是内部私有的数据隐藏,对外的接口公开。struct声明的类中的成员默认是公开的,class声明的类中的成员默认是私有的,如果类外需要访问私有的成员变量就通过成员函数来访问。一般都需要手动指定成员的访问属性: |
class 类名{
public:
公有成员;
protected:
受保护成员;
private:
私有成员;
};
构造函数
1.概念
在创建一个对象的时候,可能会需要将其中成员进行初始化的情况这可以使用构造函数,构造函数会在类构造对象时自动调用一次,其作用就是初始化对象,处于类内部,它是一个特殊的函数,它必须和类同名,而且没有返回值,其访问属性必须时公开的。
2.对象的构造过程
a.根据对象的大小分配空间(为成员变量分配)
b.检查成员变量的类型,基本类型则什么都不做,类类型就调用该类的构造函数
c.调用对象对应类的构造函数
3.构造函数的重载
一个类可以有多个构造函数,这些构造函数构成重载关系,构造对象可以传参数,传参数的方法就是在对象名后加小括号,小括号写上构造函数的实参。注意:构造函数可以有默认值,但是不要和重载发生冲突。
4.初始化参数列表
当类中的成员有引用或const时,需要在调用构造函数之前将它们进行初始化,在构造函数的参数之后,函数语句体之前,使用初始化参数列表 来实现在调用构造函数之前对成员初始化,语法如下:
class A{
public:
A():/*初始化参数列表*/{
//.....
}
};
//初始化参数列表
构造函数名(形参列表):初始化成员1(值1),初始化成员2(值2),......{
函数语句体
}
5.this指针
this指针用在类内部的成员函数和构造函数中,代表的是调用该函数的对象/构造的对象。
this指针的用法:
a.可以在成员函数和构造函数中,使用this指针对重名的函数形参和成员变量做区分;
b.this作为函数参数和返回值。
实验程序
#include <iostream>
using namespace std;
class A{
public:
//构造函数
A(){cout<<"A()"<<endl;}
};
class students{
public:
//构造函数
students(int age, int weight, int& m_num, int m_height):height(m_height),num(m_num)
{
cout<<"students(int&,int)"<<endl;
age = 10; //根据就近原则这个代表的是局部变量age
this->age = 15; //当需要使用成员的age时,需要加上this指针,因为重名了
weight = 5.5;
this->weight = 6.0;
name = "xiaofei";
}
//构造函数的重载
students(int m_age, int& m_num, int m_height, float m_weight=4.3f,string m_name="xiaohua"):height(m_height),num(m_num)
{
cout<<"students(int,int&,int,float,string)"<<endl;
age = m_age;
weight = m_weight;
name = m_name;
}
//成员函数
students *show()
{
//哪个对象调用函数show(),this就代表谁
cout<<this->name<<":"<<this->age<<":"<<this->num<<":"<<this->height<<":"<<this->weight<<endl;
return this;
}
void run()
{
cout<<this->name<<":run...."<<endl;
}
private:
int age;
string name;//C++提供的字符串类
float weight;
const int height;
int& num;
A a;
};
int main()
{
int num = 10;
int height = 130;
students xiaohua(8, num, 120, 50);
xiaohua.show();
students xiaofei(10, 60, num, height);
xiaofei.show()->show()->show()->run(); //程序show()函数会返回响应对象的指针,可以用这个指针继续访问其中成员
return 0;
}
输出结果
总结
1.类中的成员一般公开的写前面,私有的写最后;
2.如果类没有构造函数,编译器会在编译时自动生成一个,改函数什么也不做,如果类有构造函数,编译器就不会坐这个工作;
3.类中函数访问成员变量时,尽量使用this指针,避免出现歧义;
4.类的前置声明:声明一个类名,类中的具体信息在之后的代码中定义,当使用类时,类还没有实现可以使用类的前置声明:
class 类名;//前置声明