从今天开始,我们将要接触到c++最主要的内容:面向对象编程。
面向对象编程有以下几个特性:
抽象:将现实中的事物抽象成类和对象
封装和数据隐藏:将我们使用的数据封装到类中,我们可以设置哪些数据不能被外界访问。
继承、多态:在原有类的基础上,创建新的类,根据传入对象类型的不同,执行不同的操作。
创建自己的类,类包含以下两个部分:
类声明:以数据成员的方式描述数据部分,以成员函数的方式描述公共接口。提供类的蓝图
类方法定义:实现类的成员函数。
我们将类的声明放在头文件中,类方法定义放在源文件中,在源文件引入类声明的头文件。如Time.h:
#ifndef TIME_H_ #define TIME_H_ class Time { private : int hour ; int minute ; int second ; public : void setTime(int h , int m , int s) ; int getHour(){ return hour ; } int getMinute(){ return minute ; } int getSecond(){ return minute ; } void setHour(int h) { hour = h ; } void setMinute(int m ){ this->minute = m ; } void setSecond(int s){ this->second = s ; } void print() ; } ;
#endif
Time.h使用#ifndef #define #endif 条件预编译指令,这样可以在多个源文件中包含该类的定义,而不会出现定义多次。
private: 标示数据是私有成员,外界不能访问,只有本类的成员函数能够使用,public:公有成员,提供外界访问的接口,还有protected,在继承时在讲解。这三个访问控制符。
声明了Time类,在类内部实现的函数默认是内联函数,也可以不再内部实现,只在实现前加inline也可成为内联函数。如:inline void Time::print() {}
在类外实现函数时,要加上Time:: 如:
void Time::setTime(int h , int m , int s ) {
hour = h ;
minute = m ;
second = s ;
}
函数内也是类的作用域中,可以直接使用数据成员,外部不再类的作用域中,要加上Time::作用域解析符 标示函数所属类。
数据成员可以是基本类型、复合类型、指针、引用等,不能使用Time类型成员,但可以使用Time指针 或引用。
#include"Time.h" //引用自定义头文件 "Time.h" 双引号 #include<iostream> //引用标准头文件 void Time::setTime(int h ,int m , int s ) { //Time:: hour = h ; minute = m ; second = s ; } void Time::print(){ using namespace std ; cout << "Hour : " << hour << " ,Minute : " << minute << " ,Second : " << second << endl ; }
则已经创建了Time类型,我们就可以使用Time来创建自己的对象了。
#include "Time.h" #include<iostream> int main(){ Time t ; //使用默认构造函数创建对象t t.setTime(12, 30 , 45) ; //调用成员函数 t.print() ; Time *pt = new Time() ; pt->setTime(10, 20 , 30) ; //指针调用成员函数 pt->print() ; delete pt ; return 0 ; }
类提供了一个特殊的函数:构造函数,用来创建对象,并 把值赋给数据成员,若自己没有定义,则系统会提供默认构造函数,什么也不执行。
构造函数没有返回值,函数名跟类同名:
//Time.h 声明 Time(int h , int m = 0 ,int s = 0) ; //可以使用默认参数 //Time.cpp Time::Time(int h , int m , int s ) { hour = h ; minute = m ; second = s ; } //main.cpp Time t = Time(12 ,23 , 34) ; // xian xing diao yong gou zao han shu Time t2(7 , 23 , 34 ) ; //yin xing diao yong gou zao han shu
当我们自己创建了构造函数后,系统就不再提供默认构造函数Time() ; 了,我们必须使用上面两种方式创建对象,我们也可以通过函数重载定义默认构造函数,即无参构造函数或提供所有默认值的函数。因为有好多地方要用到默认构造函数,所以我们尽量要提供一个。
析构函数:当用构造函数创建对象后,程序就会跟踪所创建的对象,直到该对象过期,则这时系统会自动调用该对象的特殊函数--构造函数,来完成清理工作。如:构造函数使用new关键字分配内存,则在对象注销的使用应该使用delete来释放内存,则我们可以在析构函数中调用delete来释放内存。
析构函数:~Time(){} 没返回值 函数名同类名,用~符号,无参 若我们没有定义,则系统会帮我们创建析构函数,不执行任何操作。当我们在构造函数中使用了new来分配内存时,我们应该自己创建一个析构函数。
Time t(12 , 23, 34 ) ; 创建t对象,并对对象的成员赋值。
Time t = Time(12 , 23, 34 ) ; c++标准允许编译器使用两种方式来执行该操作,一种同上面那样,另一种是:调用构造函数创建临时对象,并将该临时对象复制到对象t中,然后丢弃临时对象。
Time t1(12 , 23, 34 ) ; Time t2(12 , 23, 34 ) ; t1 = t2 ;
t1 = t2 ; 默认情况下,同结构体一样,将一个对象赋给同类型的另一个对象时,c++将源对象的每个成员的数据复制到另一个对象对应的数据成员中去,若数据成员存在指针,则可能出现两个对象的指针数据成员指向同一块内存,修改一个对象,则会影响另一个对象,则我们应该重写赋值操作符。
const成员函数:
const T t (12 , 23, 34 ) ; t.show() ; //这行代码不能执行
t.show()不能执行,因为t对象是const常量,show()成员函数不能保证在函数中是否修改了t对象成员数据。要使之能够执行,则应将show()函数定义为const成员函数。在函数声明和定义后面加const关键字,如:
//在Time类中声明 void show() const ; //在Time.cpp实现 void Time::show() const { //在const成员函数中不能修改成员数据 //// }
const成员函数不能修改成员数据,const对象只能调用const成员函数。非const对象既可以调用const成员函数,也可以调用非const成员函数。同将不需要修改的引用参数或指针参数设置为const一样,我们也应该将不需要修改成员数据的函数设置为const成员函数。
this指针,成员函数中都有个一个this指针,它指向调用该函数的对象本身,我们可以使用它来返回调用对象本身。我们要编写一个比较时间大小的成员函数
//函数声明 const Time & Time::maxTime(const Time& t) const ; //函数定义 const Time & Time::maxTime(const Time& t) const { if(this->hour == t.hour ){ if(this->minute == t.minute ) { if(this->second >= t.second) { return *this ; //返回当前对象 }else { return t ; } }else if(this->minute > t.minute ){ return *this ; }else { return t ; } }else if (this->hour > t.hour ){ return *this ; }else { return t ; } }
在const成员函数中,this的类型是指向const的指针,不能通过this来修改对象的数据成员。
在类中使用常量:
1:我们可能想到使用const定义常量size,如:
class T { const int size = 30 ; }
但这样是错误的,因为声明类只是描述类的形式,并没有分配内存空间,不能给数据成员赋值。 但我们可以使用参数序列表在创建对象时赋值:
#include<iostream> using namespace std ; class T { const int size ; public : T(int s) : size(s) {} // :size(s) 参数序列表来给size赋值 int main(){ T t(4) ; return 0 ; }
在创建对象t时,也会创建const int size成员,并用s赋值, 若不使用参数序列表也会出错。如:T(int s ) { size = s } ; 应该执行到函数内部时,数据size已经定义了,并赋值为默认0,size = s error 因为size 为const 不能修改了。
2:使用static 静态成员:因为静态成员,在对象创建之前就已经存在,是所有对象共享的数据。如:
#include<iostream> class T { static const int size ; //也可以在这里赋值的 //static 默认是public } ; const int T::size = 30 ; //赋值 int main(){ std::cout << T.size << std::endl ; }
则size即是静态的,也是个常量。
3:在类中使用枚举:
class T{ enum {size = 12 } ; double cost[size] ; //size = 12 };