首先,竞赛中并不推荐自定义“类”来解决问题,但是我们要使用本章节介绍的标准模板库(STL),需要了解一些类的基础知识。如果只是简单地使用类,那么类的使用方法和之前介绍的结构体类似。
前面介绍过结构体,我们已经知道了结构体是由一批数据组合而成的一种新的数据类型——结构体能够将一些不同类型的数据“捆绑”聚合成一个整体从而实现自定义复合型数据类型。C语言中结构体的功能较简单,C++中将结构体的功能进一步扩充(例如增加了构造函数、成员函数、重载运算符等功能)。C++还提供了一个更强大的面向对象的程序设计利器——类。
一、类
C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 C++ 的核心特性,通常被称为用户定义的类型。类用于指定对象的形式,它包含了数据表示法和用于处理数据的方法。
C++中类的基础使用方法和前面介绍的结构体相似(其实,类的使用方法相当复杂,这里只介绍最基础的),类中有成员变量,有成员函数,也有特殊的构造函数。
double r; //圆的半径r作为Circle类的成员变量
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)。
来看一个简化的描述圆的类:
double r; //圆的半径r作为Circle类的成员变量
Circle c; //定义Circle类型变量c
#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的值:
c.r = 12.56;
会出现编译错误,Dev C++中出现的编译错误提示是: 'double Circle::r' is private
,表明 Circle 类的成员变量 r 是 private(私有的),只能在类的内部(类的定义语句中)直接访问,不能在类的外部这样访问 r。我们修改一下 Circle 类的内容,将成员变量 r 设置成 public:
public: //访问修饰符,public指明后面的成员是公共的
double r; //圆的半径r作为Circle类的成员变量
Circle c; //定义Circle类型变量c
#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的成员函数、计算圆周长和面积的成员函数,最后还重载了一些运算符。
public: //(public冒号:后面的成员都是public)
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){
bool operator >= (const Circle &a,const Circle &b){
Circle c1(5.6),c2(7.8); //调用构造函数初始化Circle变量
//因为成员r是private,不能使用c1.r直接访问
//详见上面getR成员函数中的语句:return this->r;
if(c1<c2) cout<<"c1<c2"<<endl; //类中重载了运算符 <
else if(c2>c1) cout<<"c2>c1"<<endl; //类中重载了运算符 >
else if(c1==c2) cout<<"c1==c2"<<endl; //类中重载了运算符 ==
if(c1==c2) cout<<"c1==c2"<<endl; //类中重载了运算符 ==
Circle *pc = new Circle(8.75);
cout<<pc->length()<<endl;
#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有丰富的构造函数:
string s; //调用默认构造函数,s为空字符串
string s1("Hello World"); //构造函数:初始化s1为字符串常量"Hello World"
string s2(s1); //构造函数:初始化s2为变量s1的值
string s3(s1,4); //构造函数:初始化s3为s1的子串(从第4个字符开始取)
string s4(s1,4,3); //构造函数:初始化s4为s1的子串(从第4个字符开始取,一共3个)
char cstr[] = "Nice to meet you!"; //C语言用字符数组存储的字符串
string s5(cstr); //构造函数:初始化s5为字符数组存储的字符串
string s6(cstr,6); //构造函数:初始化s6为字符数组存储的字符串的前6位子串
string s7(12,'*'); //构造函数:s7初始化为12个'*'字符组成的字符串
#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有丰富的成员函数:
string s1("Hello World");
string s2("Nice to meet you");
cout<<s1.at(0)<<endl; //cout<<s1[0]<<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;
//replace将指定位置开始的指定长度的内容替换成另一个字符串
cout<<s2.substr(8,4)<<endl;
cout<<s2.substr(8)<<endl;
cout<<s1<<"\t"<<s2<<endl;
//clear清空字符串内容(成为空串),empty判断是否是空字符串
if(s1.empty()) cout<<"s1 is empty string"<<endl;
#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中还重载了很多运算符:
//重载了赋值运算符,将字符串常量直接赋值给string变量
string s1 = "Hello World";
string s2 = "Nice to meet you";
//重载了[]运算符,通过下标方式访问字符串内部的字符(取值赋值均可)
//重载了+运算符,实现了向字符串末尾追加内容(拼接)
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;
#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;
}