NOIP学习小站
西安交通大学附属中学航天学校

首先,竞赛中并不推荐自定义“类”来解决问题,但是我们要使用本章节介绍的标准模板库(STL),需要了解一些类的基础知识。如果只是简单地使用类,那么类的使用方法和之前介绍的结构体类似。

前面介绍过结构体,我们已经知道了结构体是由一批数据组合而成的一种新的数据类型——结构体能够将一些不同类型的数据“捆绑”聚合成一个整体从而实现自定义复合型数据类型。C语言中结构体的功能较简单,C++中将结构体的功能进一步扩充(例如增加了构造函数、成员函数、重载运算符等功能)。C++还提供了一个更强大的面向对象的程序设计利器——类。

一、类

C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 C++ 的核心特性,通常被称为用户定义的类型。类用于指定对象的形式,它包含了数据表示法和用于处理数据的方法。

C++中类的基础使用方法和前面介绍的结构体相似(其实,类的使用方法相当复杂,这里只介绍最基础的),类中有成员变量,有成员函数,也有特殊的构造函数。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
//Circle类
class Circle{
double r; //圆的半径r作为Circle类的成员变量
//默认无参数构造函数
Circle(){
this->r = 0;
}
//带参数构造函数
Circle(double r){
this->r = r;
}
//成员函数:计算返回圆周长
double length(){
return 2*3.14*this->r;
}
//成员函数:计算返回圆面积
double area(){
return 3.14*this->r*this->r;
}
};
//Circle类 class Circle{ double r; //圆的半径r作为Circle类的成员变量 //默认无参数构造函数 Circle(){ this->r = 0; } //带参数构造函数 Circle(double r){ this->r = r; } //成员函数:计算返回圆周长 double length(){ return 2*3.14*this->r; } //成员函数:计算返回圆面积 double area(){ return 3.14*this->r*this->r; } };
//Circle类
class Circle{
	double r;	//圆的半径r作为Circle类的成员变量
	//默认无参数构造函数 
	Circle(){
		this->r = 0;
	}
	//带参数构造函数 
	Circle(double r){
		this->r = r;
	}
	//成员函数:计算返回圆周长
	double length(){
		return 2*3.14*this->r;
	}
	//成员函数:计算返回圆面积 
	double area(){
		return 3.14*this->r*this->r;
	}
};

细看上面的代码,会发现C++中类(简单实用是)和结构体的使用很相似,只不过定义类时,使用的是class关键字。

二、访问修饰符

类有一套特殊的设置成员变量和成员函数的访问机制——对于类的成员变量和成员函数,需要指定其是公共的(public)或者是私有的(private)或者是受保护的(protected)。

来看一个简化的描述圆的类:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include<iostream>
using namespace std;
//Circle类
class Circle{
double r; //圆的半径r作为Circle类的成员变量
};
int main()
{
Circle c; //定义Circle类型变量c
return 0;
}
#include<iostream> using namespace std; //Circle类 class Circle{ double r; //圆的半径r作为Circle类的成员变量 }; int main() { Circle c; //定义Circle类型变量c return 0; }
#include<iostream>
using namespace std;
//Circle类
class Circle{
	double r;	//圆的半径r作为Circle类的成员变量 
};
int main()
{	
	Circle c;	//定义Circle类型变量c 
	return 0;
}

C++中类和结构体的使用很相似,但是还有细节上的不同。这里尝试在 main 函数中,通过类似于结构体的“变量名.成员名”的形式来设置 Circle 类型变量c的成员变量r的值:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
c.r = 12.56;
c.r = 12.56;
c.r = 12.56; 

会出现编译错误,Dev C++中出现的编译错误提示是: 'double Circle::r' is private,表明 Circle 类的成员变量 r 是 private(私有的),只能在类的内部(类的定义语句中)直接访问,不能在类的外部这样访问 r。我们修改一下 Circle 类的内容,将成员变量 r 设置成 public:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include<iostream>
using namespace std;
//Circle类
class Circle{
public: //访问修饰符,public指明后面的成员是公共的
double r; //圆的半径r作为Circle类的成员变量
};
int main()
{
Circle c; //定义Circle类型变量c
c.r = 12.56;
cout<<c.r<<endl;
return 0;
}
#include<iostream> using namespace std; //Circle类 class Circle{ public: //访问修饰符,public指明后面的成员是公共的 double r; //圆的半径r作为Circle类的成员变量 }; int main() { Circle c; //定义Circle类型变量c c.r = 12.56; cout<<c.r<<endl; return 0; }
#include<iostream>
using namespace std;
//Circle类
class Circle{
	public:      //访问修饰符,public指明后面的成员是公共的
	double r;	//圆的半径r作为Circle类的成员变量 
};
int main()
{	
	Circle c;	//定义Circle类型变量c
	c.r = 12.56;
	cout<<c.r<<endl; 
	return 0;
}

现在成员变量 r 是public(公共的),在类的外部就可以通过 c.r 的形式来访问了。

上面的例子说明了简单使用类时,与结构体相比较,类额外有成员变量和成员函数的访问机制。如果没有指明成员的访问修饰符,那么默认为是 private(私有的),这也是程序最开始编译出错的原因。

三、类的使用举例

我们来定义一个功能丰富的描述圆的类Circle。成员变量很简单就是一个double r;用来描述圆的半径,可以设置成private。设计两个构造函数用来初始化Circle变量,还设计有获取和设置圆半径r的成员函数、计算圆周长和面积的成员函数,最后还重载了一些运算符。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include<iostream>
using namespace std;
//Circle类
class Circle{
private:
double r;
public: //(public冒号:后面的成员都是public)
//默认构造函数
Circle(){
this->r = 0;
}
//一个参数的构造函数
Circle(double r){
this->r = r;
}
//成员函数:返回圆半径
double getR() const{
return this->r;
}
//成员函数:设置圆的半径
void setR(double r){
this->r = r;
}
//成员函数:计算返回圆周长
double length() const{
return 2*3.14*this->r;
}
//成员函数:计算返回圆面积
double area() const{
return 3.14*this->r*this->r;
}
};
//重载运算符 <
bool operator < (const Circle &a,const Circle &b){
return a.getR()<b.getR();
}
//重载运算符 >
bool operator > (const Circle &a,const Circle &b){
return a.getR()>b.getR();
}
//重载运算符 ==
bool operator == (const Circle &a,const Circle &b){
return a.getR()==b.getR();
}
//重载运算符 <=
bool operator <= (const Circle &a,const Circle &b){
//借助已经重载的<和==运算符
return a<b || a==b;
}
//重载运算符 >=
bool operator >= (const Circle &a,const Circle &b){
//借助已经重载的>和==运算符
return a>b || a==b;
}
int main()
{
Circle c1(5.6),c2(7.8); //调用构造函数初始化Circle变量
//因为成员r是private,不能使用c1.r直接访问
//但是可以通过getR获取成员变量r的值
//详见上面getR成员函数中的语句:return this->r;
cout<<c1.getR()<<endl;
//调用length和area计算周长和面积
cout<<c1.length()<<endl;
cout<<c1.area()<<endl;
//通过重载运算符进行比较
if(c1<c2) cout<<"c1<c2"<<endl; //类中重载了运算符 <
else if(c2>c1) cout<<"c2>c1"<<endl; //类中重载了运算符 >
else if(c1==c2) cout<<"c1==c2"<<endl; //类中重载了运算符 ==
//调用成员函数设置半径
c2.setR(c1.getR());
if(c1==c2) cout<<"c1==c2"<<endl; //类中重载了运算符 ==
//new初始化Circle指针pc
Circle *pc = new Circle(8.75);
cout<<pc->getR()<<endl;
cout<<pc->length()<<endl;
cout<<pc->area()<<endl;
return 0;
}
#include<iostream> using namespace std; //Circle类 class Circle{ private: double r; public: //(public冒号:后面的成员都是public) //默认构造函数 Circle(){ this->r = 0; } //一个参数的构造函数 Circle(double r){ this->r = r; } //成员函数:返回圆半径 double getR() const{ return this->r; } //成员函数:设置圆的半径 void setR(double r){ this->r = r; } //成员函数:计算返回圆周长 double length() const{ return 2*3.14*this->r; } //成员函数:计算返回圆面积 double area() const{ return 3.14*this->r*this->r; } }; //重载运算符 < bool operator < (const Circle &a,const Circle &b){ return a.getR()<b.getR(); } //重载运算符 > bool operator > (const Circle &a,const Circle &b){ return a.getR()>b.getR(); } //重载运算符 == bool operator == (const Circle &a,const Circle &b){ return a.getR()==b.getR(); } //重载运算符 <= bool operator <= (const Circle &a,const Circle &b){ //借助已经重载的<和==运算符 return a<b || a==b; } //重载运算符 >= bool operator >= (const Circle &a,const Circle &b){ //借助已经重载的>和==运算符 return a>b || a==b; } int main() { Circle c1(5.6),c2(7.8); //调用构造函数初始化Circle变量 //因为成员r是private,不能使用c1.r直接访问 //但是可以通过getR获取成员变量r的值 //详见上面getR成员函数中的语句:return this->r; cout<<c1.getR()<<endl; //调用length和area计算周长和面积 cout<<c1.length()<<endl; cout<<c1.area()<<endl; //通过重载运算符进行比较 if(c1<c2) cout<<"c1<c2"<<endl; //类中重载了运算符 < else if(c2>c1) cout<<"c2>c1"<<endl; //类中重载了运算符 > else if(c1==c2) cout<<"c1==c2"<<endl; //类中重载了运算符 == //调用成员函数设置半径 c2.setR(c1.getR()); if(c1==c2) cout<<"c1==c2"<<endl; //类中重载了运算符 == //new初始化Circle指针pc Circle *pc = new Circle(8.75); cout<<pc->getR()<<endl; cout<<pc->length()<<endl; cout<<pc->area()<<endl; return 0; }
#include<iostream>
using namespace std;
//Circle类
class Circle{
    private:
    double r;
    
    public:        //(public冒号:后面的成员都是public)
    //默认构造函数 
    Circle(){
        this->r = 0;
    }
    //一个参数的构造函数
    Circle(double r){
        this->r = r;
    }
    //成员函数:返回圆半径 
    double getR() const{
        return this->r;
    }
    //成员函数:设置圆的半径 
    void setR(double r){
        this->r = r;
    }
    //成员函数:计算返回圆周长 
    double length() const{
        return 2*3.14*this->r;
    }
    //成员函数:计算返回圆面积 
    double area() const{
        return 3.14*this->r*this->r;
    }
};
//重载运算符 <  
bool operator < (const Circle &a,const Circle &b){
	return a.getR()<b.getR();
}
//重载运算符 > 
bool operator > (const Circle &a,const Circle &b){
	return a.getR()>b.getR();
}
//重载运算符 == 
bool operator == (const Circle &a,const Circle &b){
	return a.getR()==b.getR();
}
//重载运算符 <=
bool operator <= (const Circle &a,const Circle &b){
	//借助已经重载的<和==运算符 
	return a<b || a==b;
}
//重载运算符 >=  
bool operator >= (const Circle &a,const Circle &b){
	//借助已经重载的>和==运算符
	return a>b || a==b;
}
int main()
{    
    Circle c1(5.6),c2(7.8);    //调用构造函数初始化Circle变量
    
    //因为成员r是private,不能使用c1.r直接访问
    //但是可以通过getR获取成员变量r的值
    //详见上面getR成员函数中的语句:return this->r; 
    cout<<c1.getR()<<endl;
    
    //调用length和area计算周长和面积 
    cout<<c1.length()<<endl;
    cout<<c1.area()<<endl;
    
    //通过重载运算符进行比较 
    if(c1<c2) cout<<"c1<c2"<<endl;           //类中重载了运算符 < 
    else if(c2>c1) cout<<"c2>c1"<<endl;      //类中重载了运算符 >
    else if(c1==c2) cout<<"c1==c2"<<endl;    //类中重载了运算符 ==
    
    //调用成员函数设置半径 
    c2.setR(c1.getR());
    if(c1==c2) cout<<"c1==c2"<<endl;    //类中重载了运算符 ==
    
    //new初始化Circle指针pc 
    Circle *pc = new Circle(8.75);
    cout<<pc->getR()<<endl;
    cout<<pc->length()<<endl;
    cout<<pc->area()<<endl;
    return 0;
}

四、再看string类

前面介绍字符串的时候提到,C++中使用了全新的数据类型string来处理字符串,其实string就是C++中内置的一个专门用于处理字符串的类(这个类定义语句在头文件string中,所以我们使用string时需要include这个头文件)。这里不讨论string的内部实现,我们通过string的用法来进一步认识类的使用。

string有丰富的构造函数:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s; //调用默认构造函数,s为空字符串
string s1("Hello World"); //构造函数:初始化s1为字符串常量"Hello World"
cout<<s1<<endl;
string s2(s1); //构造函数:初始化s2为变量s1的值
cout<<s2<<endl;
string s3(s1,4); //构造函数:初始化s3为s1的子串(从第4个字符开始取)
cout<<s3<<endl;
string s4(s1,4,3); //构造函数:初始化s4为s1的子串(从第4个字符开始取,一共3个)
cout<<s4<<endl;
char cstr[] = "Nice to meet you!"; //C语言用字符数组存储的字符串
string s5(cstr); //构造函数:初始化s5为字符数组存储的字符串
cout<<s5<<endl;
string s6(cstr,6); //构造函数:初始化s6为字符数组存储的字符串的前6位子串
cout<<s6<<endl;
string s7(12,'*'); //构造函数:s7初始化为12个'*'字符组成的字符串
cout<<s7<<endl;
return 0;
}
#include<iostream> #include<string> using namespace std; int main() { string s; //调用默认构造函数,s为空字符串 string s1("Hello World"); //构造函数:初始化s1为字符串常量"Hello World" cout<<s1<<endl; string s2(s1); //构造函数:初始化s2为变量s1的值 cout<<s2<<endl; string s3(s1,4); //构造函数:初始化s3为s1的子串(从第4个字符开始取) cout<<s3<<endl; string s4(s1,4,3); //构造函数:初始化s4为s1的子串(从第4个字符开始取,一共3个) cout<<s4<<endl; char cstr[] = "Nice to meet you!"; //C语言用字符数组存储的字符串 string s5(cstr); //构造函数:初始化s5为字符数组存储的字符串 cout<<s5<<endl; string s6(cstr,6); //构造函数:初始化s6为字符数组存储的字符串的前6位子串 cout<<s6<<endl; string s7(12,'*'); //构造函数:s7初始化为12个'*'字符组成的字符串 cout<<s7<<endl; return 0; }
#include<iostream>
#include<string>
using namespace std;
int main()
{	
	string s;		//调用默认构造函数,s为空字符串
	
	string s1("Hello World"); //构造函数:初始化s1为字符串常量"Hello World" 
	cout<<s1<<endl;
	
	string s2(s1);	//构造函数:初始化s2为变量s1的值	
	cout<<s2<<endl;
	
	string s3(s1,4); //构造函数:初始化s3为s1的子串(从第4个字符开始取) 
	cout<<s3<<endl; 
	
	string s4(s1,4,3); //构造函数:初始化s4为s1的子串(从第4个字符开始取,一共3个) 
	cout<<s4<<endl; 
	
	char cstr[] = "Nice to meet you!";		//C语言用字符数组存储的字符串 
	string s5(cstr);	//构造函数:初始化s5为字符数组存储的字符串 
	cout<<s5<<endl; 
	
	string s6(cstr,6);	//构造函数:初始化s6为字符数组存储的字符串的前6位子串 
	cout<<s6<<endl;
	
	string s7(12,'*');	//构造函数:s7初始化为12个'*'字符组成的字符串 
	cout<<s7<<endl;
	return 0;
}

string有丰富的成员函数:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int main()
{
string s1("Hello World");
string s2("Nice to meet you");
//length或者size获取字符串长度
cout<<s1.length()<<endl;
cout<<s1.size()<<endl;
//at获取指定位置的字符
cout<<s1.at(0)<<endl; //cout<<s1[0]<<endl;
//c_str返回string对应的字符数组指针
cout<<s1.c_str()<<endl;
char s[110];
strcpy(s,s1.c_str());
cout<<s<<endl;
//find,rfind查找字符串(或字符)出现位置
//查找还有find_first_of、find_last_of、find_first_not_of、find_last_not_of等
cout<<s1.find("llo")<<endl;
cout<<s1.rfind('l')<<endl;
//append向字符串末尾追加内容
s1.append("!");
cout<<s1<<endl;
//insert从指定位置插入另一个字符串
s1.insert(0,"Say ");
cout<<s1<<endl;
//replace将指定位置开始的指定长度的内容替换成另一个字符串
s1.replace(4,5,"hi");
cout<<s1<<endl;
//erase清除指定位置开始的指定长度的内容
s1.erase(4,3);
cout<<s1<<endl;
//substr从指定位置获取制定长度的子串
cout<<s2.substr(8,4)<<endl;
cout<<s2.substr(8)<<endl;
//swap交换string的值
s1.swap(s2);
cout<<s1<<"\t"<<s2<<endl;
//clear清空字符串内容(成为空串),empty判断是否是空字符串
s1.clear();
cout<<s1.length()<<endl;
if(s1.empty()) cout<<"s1 is empty string"<<endl;
return 0;
}
#include<iostream> #include<string> #include<cstring> using namespace std; int main() { string s1("Hello World"); string s2("Nice to meet you"); //length或者size获取字符串长度 cout<<s1.length()<<endl; cout<<s1.size()<<endl; //at获取指定位置的字符 cout<<s1.at(0)<<endl; //cout<<s1[0]<<endl; //c_str返回string对应的字符数组指针 cout<<s1.c_str()<<endl; char s[110]; strcpy(s,s1.c_str()); cout<<s<<endl; //find,rfind查找字符串(或字符)出现位置 //查找还有find_first_of、find_last_of、find_first_not_of、find_last_not_of等 cout<<s1.find("llo")<<endl; cout<<s1.rfind('l')<<endl; //append向字符串末尾追加内容 s1.append("!"); cout<<s1<<endl; //insert从指定位置插入另一个字符串 s1.insert(0,"Say "); cout<<s1<<endl; //replace将指定位置开始的指定长度的内容替换成另一个字符串 s1.replace(4,5,"hi"); cout<<s1<<endl; //erase清除指定位置开始的指定长度的内容 s1.erase(4,3); cout<<s1<<endl; //substr从指定位置获取制定长度的子串 cout<<s2.substr(8,4)<<endl; cout<<s2.substr(8)<<endl; //swap交换string的值 s1.swap(s2); cout<<s1<<"\t"<<s2<<endl; //clear清空字符串内容(成为空串),empty判断是否是空字符串 s1.clear(); cout<<s1.length()<<endl; if(s1.empty()) cout<<"s1 is empty string"<<endl; return 0; }
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int main()
{	 
	string s1("Hello World");
	string s2("Nice to meet you");
	
	//length或者size获取字符串长度 
	cout<<s1.length()<<endl;
	cout<<s1.size()<<endl;
	
	//at获取指定位置的字符 
	cout<<s1.at(0)<<endl; 		//cout<<s1[0]<<endl;
	
	//c_str返回string对应的字符数组指针 
	cout<<s1.c_str()<<endl;
	char s[110];
	strcpy(s,s1.c_str());
	cout<<s<<endl;
	
	//find,rfind查找字符串(或字符)出现位置
	//查找还有find_first_of、find_last_of、find_first_not_of、find_last_not_of等 
	cout<<s1.find("llo")<<endl; 
	cout<<s1.rfind('l')<<endl; 

	//append向字符串末尾追加内容 
	s1.append("!");
	cout<<s1<<endl;
	
	//insert从指定位置插入另一个字符串 
	s1.insert(0,"Say ");
	cout<<s1<<endl; 
	
	//replace将指定位置开始的指定长度的内容替换成另一个字符串 
	s1.replace(4,5,"hi");
	cout<<s1<<endl;
	
	//erase清除指定位置开始的指定长度的内容 
	s1.erase(4,3);
	cout<<s1<<endl;
	
	//substr从指定位置获取制定长度的子串
	cout<<s2.substr(8,4)<<endl;
	cout<<s2.substr(8)<<endl; 
	
	//swap交换string的值 
	s1.swap(s2);
	cout<<s1<<"\t"<<s2<<endl;
	
	//clear清空字符串内容(成为空串),empty判断是否是空字符串 
	s1.clear();
	cout<<s1.length()<<endl;
	if(s1.empty()) cout<<"s1 is empty string"<<endl;
	return 0;
}

string中还重载了很多运算符:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include<iostream>
#include<string>
using namespace std;
int main()
{
//重载了赋值运算符,将字符串常量直接赋值给string变量
string s1 = "Hello World";
string s2 = "Nice to meet you";
//重载了[]运算符,通过下标方式访问字符串内部的字符(取值赋值均可)
cout<<s1[0]<<endl;
s1[0] = 'h';
cout<<s1<<endl;
//重载了+运算符,实现了向字符串末尾追加内容(拼接)
cout<<s1+s2<<endl;
cout<<s1+'Y'<<endl;
//重载了+=运算符,实现了自加效果
string ss = "Hello";
ss += " World!";
cout<<ss<<endl;
//重载了一系列比较运算符
if(s1==s2) cout<<s1<<" == "<<s2<<endl;
if(s1>s2) cout<<s1<<" > "<<s2<<endl;
if(s1>=s2) cout<<s1<<" >= "<<s2<<endl;
if(s2<s1) cout<<s2<<" < "<<s1<<endl;
if(s2<=s1) cout<<s2<<" <= "<<s1<<endl;
return 0;
}
#include<iostream> #include<string> using namespace std; int main() { //重载了赋值运算符,将字符串常量直接赋值给string变量 string s1 = "Hello World"; string s2 = "Nice to meet you"; //重载了[]运算符,通过下标方式访问字符串内部的字符(取值赋值均可) cout<<s1[0]<<endl; s1[0] = 'h'; cout<<s1<<endl; //重载了+运算符,实现了向字符串末尾追加内容(拼接) cout<<s1+s2<<endl; cout<<s1+'Y'<<endl; //重载了+=运算符,实现了自加效果 string ss = "Hello"; ss += " World!"; cout<<ss<<endl; //重载了一系列比较运算符 if(s1==s2) cout<<s1<<" == "<<s2<<endl; if(s1>s2) cout<<s1<<" > "<<s2<<endl; if(s1>=s2) cout<<s1<<" >= "<<s2<<endl; if(s2<s1) cout<<s2<<" < "<<s1<<endl; if(s2<=s1) cout<<s2<<" <= "<<s1<<endl; return 0; }
#include<iostream>
#include<string>
using namespace std;
int main()
{    
    //重载了赋值运算符,将字符串常量直接赋值给string变量 
    string s1 = "Hello World";
    string s2 = "Nice to meet you";
    
    //重载了[]运算符,通过下标方式访问字符串内部的字符(取值赋值均可) 
    cout<<s1[0]<<endl;
    s1[0] = 'h';
    cout<<s1<<endl; 
    
    //重载了+运算符,实现了向字符串末尾追加内容(拼接)
    cout<<s1+s2<<endl; 
    cout<<s1+'Y'<<endl;
    //重载了+=运算符,实现了自加效果
    string ss = "Hello";
    ss += " World!";
    cout<<ss<<endl;
    
    //重载了一系列比较运算符
    if(s1==s2) cout<<s1<<" == "<<s2<<endl;
    if(s1>s2) cout<<s1<<" > "<<s2<<endl;
    if(s1>=s2) cout<<s1<<" >= "<<s2<<endl;
    if(s2<s1) cout<<s2<<" < "<<s1<<endl;
    if(s2<=s1) cout<<s2<<" <= "<<s1<<endl;
    return 0;
}

登录

注册