数据类型是各个变量的归类,而变量则是某个数据类型的具体表现,因此称变量为数据类型的一个实例(instance)。各个变量都有他们的属性:内容和占用内存空间等等;各个变量都有他们的操作:算术运算或逻辑运算等等。从这个角度来看,类和对象的关系就如同数据类型和变量的关系。不妨将类看作一种自定义的数据类型,那么对象就是一种属于该类型的变量。
类的定义:
class Name
{
public:
//类的公有接口
private:
//私有的成员函数
//私有的数据成员定义
protected:
//
};
类的定义由类头和类体两部分组成。类头由关键字class开头,然后是类名,其命名规则与一般标识符的命名规则一致。类体包括所有的细节,并放在一对花括号中。类的定义也是一个语句,所以要有分号结尾,否则会产生编译错误。
类体定义类的成员,它支持两种类型的成员:
(1)数据成员,它们指定了该类对象的内部表示。
(2)成员函数,他们指定了该类的操作。
类成员有3种不同的访问权限:
(1) 公有(public)成员可以在类外访问。
(2) 私有(private)成员只能被该类的成员函数访问。
(3) 保护(protected)成员只能被该类的成员函数或派生类的成员函数访问。
数据成员通常是私有的,成员函数通常有一部分是公有的,一部分是私有的。公有的函数可以在类外被访问,也称之为类的接口。可以为各个数据成员和成员函数指定合适的访问权限。
如果在定义或声明时不说明该成员数据(或成员函数)是公有的还是私有的,则默认为私有的。所以先定义公有再定义私有,方便阅读代码时能够区分。虽然在定义时可以有多个public或private保留字,但是不推荐那样的写法。
定义完一个类之后务必要在最后加上一个分号。
可以将一个类定义在一个头文件中,然后在源文件中包含这个头文件。
#include"class.h" //要注意这里必须用双引号,而不能用 < >
成员函数是属于某一个类的,所以只能在类的内部声明。
如果一个类的某个成员函数是私有的,那么它只能被这个类的其他成员函数调用。
成员函数的定义:
成员函数与普通函数的不同之处,在于成员函数是属于某一个类的,而不能被随意地调用。在定义一个成员函数的时候就要用到::操作符,它表示该函数是属于某一个类的,称为域解析操作符。因此在类定义结束后,定义一个成员函数的格式如下:
返回值类型 类名::函数名(参数列表)
{
语句;
}
事实上,成员函数也是可以在类的定义中定义的(此时不需要域解析操作符),但是从程序的运行效率、可读性、美观性考虑,建议将成员函数的定义完全放在类定义的外面。
在成员函数定义中,可以看出成员数据(或成员函数)在成员函数中可以直接使用。以前使用一个对象的公有成员数据时,要写作“对象名.成员数据”,但是在成员函数中不需要也不能那样写。
在类中,可以使用const这个保留字来保护成员数据不被成员函数改变。这种成员函数称为常成员函数。它的写法就是在函数的参数表后面加上一个const,比如:
void intread (void) const;//通过该函数读取数据,但不能改变任何成员数据
{函数体;}
使用常成员函数,就保证了成员数据的安全。
成员函数的重载:
和普通函数类似,在一个类中也可以有成员函数重载。成员函数的重载在规则上和普通函数也并无差别。
bool set(int i);//重载,通过该函数修改idata
bool set(char c);// 重载,通过该函数修改cdata
对象指针:一个指向对象的指针
由于类和结构的相似性,对象指针和结构指针的使用也是相似的。也是使用箭头操作符->来访问该指针所指向的对象的成员数据或成员函数。
//class.h 包含类的定义
#ifndef __A__
#define __A__
#include<string>
using namespace std;
class Date //类的定义
{
private:
int year,month,day;
public:
void set(int,int,int);
void set(string); //重载成员函数
bool isleapyear() const; //常成员函数
void print()const; //常成员函数
};
#endif
//class.cpp 相应类的成员函数的定义
#include<iostream>
#include<iomanip>
#include"class.h"
using namespace std;
void Date::set(int y,int m,int d) //成员函数的定义
{
year=y,month=m,day=d;
}
void Date::set(string str)
{
year=atoi(str.substr(0,4).c_str());
month=atoi(str.substr(5,2).c_str());
day=atoi(str.substr(8,2).c_str());
}
bool Date::isleapyear() const
{
return (year%4==0&&year%100!=0)||(year%400==0);
}
void Date::print() const
{
cout<<setfill('0');
cout<<setw(4)<<year<<"-"<<setw(2)<<month<<"-"<<setw(2)<<day<<endl;
cout<<setfill(' ');
}
//main.cpp 主函数
#include<iostream>
#include"class.h"
using namespace std;
int main()
{
Date D1;
D1.set(2000,12,6);
if(D1.isleapyear())
D1.print();
Date* D2=new Date; //对象指针
D2->set("2000-12-07"); //对象指针的操作( -> )
if(D2->isleapyear())
D2->print();
return 0;
}
严格意义下的数据类型,不但要有数据的内部表示以及表示范围,还要有数据的操作,即如何代表复合数据的整体来访问它们,而struct描述并没有涉及其操作。
C++的内部数据类型名称全是由小写字母组成的,因此人为定义的数据类型名称采用大写字母开头的命名方法可以很容易区分。
在内部数据类型以及结构型中,称所创建的实体为变量;而在类中,称所创建的实体为对象。一般来说,对象是拥有操作的数据实体,是由类创建的;而变量是由内部数据类型以及单纯数据组合而定义的数据类型创建的,它们“不”拥有操作。对象和变量的差别并不明显,因为内部数据类型其实也拥有许多默认的操作,如整型变量可以进行+、-、*、/等操作。所以,只要是由数据类型创建的实体,都是对象,而变量只不过是对象的一种简单形式而已。
成员函数在调用时因为捆绑了对象,其实已经含有对象参数了,所以不需要传递对象参数;而普通函数调用时是不捆绑对象的,所以为了得到对象信息,需要明确传递一个对象参数。
成员函数一定从属于类,所以不能独立存在,这是它与普通函数的重要区别。这也就是在定义成员函数时,函数名前要加类名的道理。