1、类与对象的定义
类:将数据以及数据上的操作封装在一起(月饼模型)
对象:具有类类型的变量 (填入月饼的馅儿,豆沙馅,红糖五仁,莲蓉蛋黄)
2、类与对象的关系
对象是对客观事物的抽象,类是对对象的抽象
类是一种抽象的数据结构
对象是类的实例,类是对象的模板。
//定义圆
//实体:圆类
//属性(数据):半径 r
//行为(函数):求圆面积 求圆周长
3、类的定义
class 类名称 //首字母最好大写
{
public:
公有成员(外部接口) //任何外部函数都可以访问
private:
私有成员 //只允许本类中的函数访问
protected:
保护型成员 //与继承有关
}
/*形式说明:
1、public和 private是访问权限修饰符
2、成员函数可以访问本类中的任何成员,需要被外界调用的函数指定为 public */
//例子
class Clock {
private:
int hour, minute, second;
public:
void setTime (int newH, int newM, int newS);
void showTime();
}; //分号很重要
//属性一般定义为private,行为一般定义为public,这样就实现了封装
//成员函数定义方法
/* 返回类型 类名 :: 成员函数名(参数说明) {
函数体
} */
//举例
#include <iostream>
using namespace std;
class Clock {
private:
int hour, minute, second;
public:
void setTime(int newH = 0, int newM = 0, int newS = 0);
void showTime();
};
//成员函数
void Clock :: setTime(int newH, int newM, int newS) {
hour = newH;
minute = newM;
second = newS;
}
void showTime() {
cout << hour << ":" << minute << ":" << second;
}
//主程序
int main () {
Clock myClock; //定义对象,像是产生了某种具体口味的月饼
//注:不要写成 Clock myClock();
//我们没有定义构造函数,系统自动搞了一个缺省的构造函数,因此可以这么定义对象。如果我们定义了有几个参数的构造函数,那么这样定义对象就是错误的
myClock.setTime(8, 30, 30); //调用成员函数,像极了python
myClock.showTime();
return 0;
}
4、构造函数
//一种特殊的成员函数
类名 :: 类名(参数说明)
{
初始化代码
}
/*
构造函数的特点:
1、构造函数的名字必须与类的名字相同
2、定义构造函数时不能指定返回类型(连void也不是)
3、代码与其他函数一样,但一般不直接调用(显式调用)
4、创建类的一个新对象时,会隐式地自动调用构造函数。也就是说,当程序中声明一个新对象时,程序会自动地调用该对象所属类中定义的构造函数来初始化这个对象的状态。
5、若在定义类时没有定义构造函数,c++会自动为该类创建一个缺省(default)的构造函数,这个构造函数没有任何形参,函数体为空。因此在上面第三大点里,虽然我们没有学习构造函数,但是主程序仍能正常运行
*/
//每定义一个对象,就会开辟一块内存
//举例见下面析构函数
5、析构函数
//在对象撤销时执行一些清理任务。例如在建立对象时用new开辟了一篇内存空间,delete会自动调用析构函数后释放内存
类名 :: ~类名() {
}
/* 特点:
1、必须是在类名前加上一个~,以区别于构造函数
2、不能指定返回类型
3、对象消亡时,隐式地调用析构函数,来清除这个对象占用的存储空间
4、若在定义类时没有定义析构函数,c++会自动为类创建一个缺省的析构函数。这个析构函数没有任何形式参数,且函数体为空
*/
//举例:
#include <iostream>
using namespace std;
class DemoClass {
public:
DemoClass(int i);
~DemoClass();
};
//构造函数
DemoClass :: DemoClass(int i) {
cout << "Initial value is" << i << endl;
}
//析构函数
DemoClass :: ~DemoClass() {
cout << "destructor" << endl;
}
//到此,类定义完毕
void main () {
DemoClass obj(30); //对象声明,(30)表示给构造函数传了个30,也就是说构造函数自动调用了
cout << "This is the end main()" << endl; //这条语句执行完毕胡,会自动调用析构函数
return;
}
/*因此本程序的输出为:
Initial value is 30 //自动调用构造函数,分配内存(先输出再分配)
This is the end main()
destructor //自动调用析构函数,回收内存(先输出,再回收)
*/
//因此此时Clock的类:
class Clock {
private:
int hour, minute, second;
public:
Clock(int newH, int newM, int newS); //声明构造函数,函数名和类名称完全相同
void setTime(int newH, int newM, int newS);
void showTime();
};
//增加一个构造函数的实现,两个void函数都和之前的一样
Clock :: Clock(int newH, int newM, int newS) : //会有一个冒号,成为成员列表,真的很python
hour(newH), minute(newM), second(newS) {
} //就是说明一下传入的数据都赋给Clock的什么属性,newH应该赋给hour,以此类推
//成员列表等价于:
/*
Clock :: Clock(int newH, int newM, int newS) {
hour = newH;
minute = newM;
second = newS;
}
*/
//建立对象时构造函数的作用
int main() {
Clock c(0, 0, 0); //创建了一个叫c的Clock对象,它会自动按我们成员列表里的说明来赋值,也很像结构体啦
c.showTime();
return 0;
}
//类有自己的成员函数,这是比结构体的高明之处
问题:这个时候用Clock.c创建对象是否正确?
//出错了 no matching function for call to Clock :: Clock,即调用构造函数时发现没有匹配函数。当我这样写的时候,他会去调用那个没有参数的函数,所以不匹配,因为我们的构造函数时三个参数的。(我们定义类的时候定义了构造函数。)
//所以要怎么改呢
//在类的定义里,我们定义好的构造函数之前再声明一个没有参数的构造函数Clock();这个时候问题里的创建对象方法就是正确的啦!
//定义无参构造函数,系统会给属性赋初值为1
//当我们构造Clock.c1和Clock c2(0, 0, 0)后,就形成了构造函数的重载,他们各自有独立的存储空间
构造函数细节小结:
没有定义构造函数 | 自动创造缺省的构造函数,可以Clock c;来声明对象 |
定义无参函数 | Clock c; 会自动给属性赋初值为1 |
定义有参函数 | Clock c(8, 3, 30); 传入的数要和定义的有参构造函数的形参数目一致 |
6、默认构造函数
//调用时不需要参数的构造函数都是默认构造函数
//全部参数都有默认形参值的函数也是默认构造函数
//比如同时出现:
Clock();
Clock(int newH = 0, int M = 0, int newS = 0 );
//会报错
一个类只能有一个默认构造函数