1、特性简介
1、抽象
abstract,抽象是对具体对象(问题)进行概括,抽出这一类对象的公共性质并加以描述的过程。
抽象成一个类:数据抽象+代码抽象
2、封装
将抽象出的数据成员代码、代码成员相结合,将它们视为一个整体。
实现封装:类声明中的 { }
3、继承与派生
C++语言中提供了类的继承机制,允许程序员在保持原有类特性的基础上,进行更具体、更详细的说明。
4、多态
多态,是指具有相似功能的不同函数使用同一个名称来实现
2、类和对象
1、类
类是具有相同属性和行为的一组对象的集合,它为属于该类的全部对象提供了统一的抽象描述,其内部包括
属性和行为两个主要部分
数据成员:与一般的变量声明相同,但需要将它放在类的声明体中
函数成员:在类中说明原型,可以在类外给出函数体实现,并在函数名前使用类名加以限定,也可以直接在类中给出函数体,
形成内联成员函数。允许声明重载函数和带缺省形参值的函数
内联函数成员:为了提高运行时效率,对于较简单的函数可以声明为内联形式。
隐式声明:将函数体放在类的声明中
显示声明:使用 inline 关键字
实例:
class Clock
{
public://公有成员(外部接口)
void SetTime(int NewH, int NewM, int NewS);
void ShowTime()//类内隐式内联函数
{cout << Hour << ":" << Minute << ":" << Second << endl;}
private://私有成员
int Hour, Minute, Second;
}
inline void Clock::SetTime(int NewH, int NewM, int NewS)//类外显示内联函数
{
Hour = NewH;
Minute = NewM;
Second = NewS;
}
2、对象
类的对象是该类的某一特定实体,即类类型的变量
声明形式: 类名 对象名; 如:Clock myClock;
3、完整实例
#include<iostream>
using namespace std;
class Clock
{
public:
void SetTime(int NewH = 0, int NewM = 0, int NewS = 0);
void ShowTime();
private:
int Hour, Minute, Second;
};
void Clock::SetTime(int NewH, int NewM, int NewS)
{
Hour = NewH;
Minute = NewM;
Second = NewS;
}
inline void Clock::ShowTime()
{
cout << Hour << ":" << Minute << ":" << Second << endl;
}
int main()
{
Clock myClock;
myClock.SetTime();// 设置时间为默认值
myClock.ShowTime(); //显示时间
myClock.SetTime(19,01,30);//设置时间为 19:01:30
myClock.ShowTime(); //显示时间
return 0;
}
运行结果:
3、构造函数
构造函数的作用是在对象被创建时使用特定的值构造对象,或者说将对象初始化为一个特定的状态。
在对象创建时由系统自动调用。作用:预处理
如果再程序中未声明,则系统自动产生出一个缺省形式的构造函数
允许为内联函数、重载函数、带缺省形参值的函数
操作实例:
#include<iostream>
using namespace std;
class Clock
{
public:
Clock(int NewH, int NewM, int NewS);//构造函数声明部分
void SetTime(int NewH = 0, int NewM = 0, int NewS = 0);
void ShowTime();
private:
int Hour, Minute, Second;
};
void Clock::SetTime(int NewH, int NewM, int NewS)
{
Hour = NewH;
Minute = NewM;
Second = NewS;
}
inline void Clock::ShowTime()
{
cout << Hour << ":" << Minute << ":" << Second << endl;
}
Clock::Clock(int NewH, int NewM, int NewS)//构造函数的实现
{
Hour = NewH;
Minute = NewM;
Second = NewS;
}
int main()//构造函数应用
{
Clock c(0,0,0);//隐含调用构造函数,将初始值作为实参
c.ShowTime();
c.SetTime(19,38,20);
c.ShowTime();
return 0;
}
运行结果:
4、拷贝构造函数
拷贝构造函数是一种特殊的构造函数,其形参为本类的对象引用。
如果程序员没有为类声明拷贝初始化构造函数,则编译器自己生成一个拷贝构造函数。
功能:用作为初始值的对象的每个数据成员的值,初始化将要建立的对象的对应数据成员。
#include<iostream>
using namespace std;
class Point
{
public:
Point(int xx = 0,int yy = 0){X = xx; Y = yy;}//构造函数(内联)
Point(Point &p); //拷贝构造函数
int GetX(){return X;}
int GetY(){return Y;}
private:
int X,Y;
};
Point::Point(Point &p)//拷贝构造函数的实现
{
X = p.X;
Y = p.Y;
cout << "拷贝构造函数被调用" << endl;
}
应用:
a:当用类的一个对象去初始化该类的另一个对象时系统自动调用它实现
int main()//构造函数应用
{
Point A(1,2);
Point B(A); //拷贝构造函数被调用
cout << B.GetX() << endl;
return 0;
}
b:如函数的形参为类对象,调用函数时,实参赋值给形参,系统自动调用拷贝构造函数
void fun1(Point p)
{
cout << p.GetX() << endl;
}
int main()
{
Point A(1,2);
fun1(A); //调用拷贝构造函数
return 0;
}
c:当函数的返回值是类对象时,系统自动调用拷贝构造函数
Point fun2()
{
Point A(1,2);
return A;//调用拷贝构造函数
}
int main()
{
Point B;
B = fun2();
return 0;
}
5、析构函数
完成对象被删除前的一些清理工作
在对象的生存期结束的时刻系统自动调用它,然后再释放此对象所属的空间
如果程序中未声明析构函数,编译器将自动产生一个缺省的析构函数
形式:
Class Point
{
//...
~Point();//析构函数声明
//...
}
Point::~Point()//析构函数实现
{
//...
}
6、类的组合
类的组合(也称聚集),描述的就是一个类内嵌其他类的对象作为成员的情况,他们之间的关系是一种包含与被包含的关系
当创建类的对象时,如果这个类具有内嵌对象成员,那么各个内嵌对象也将被自动创建
a:类中的成员数据是另一个类的对象
b:可以在已有的抽象的基础上实现更复杂的抽象
原则:不仅要负责对本类中的基本类型成员数据赋初值,也要对对象成员初始化
声明形式:
类名::类名(对象成员所需的形参,本类成员形参)
:对象1(参数),对象2(参数),......
{ 本类初始化 }
构造函数调用顺序:先调用内嵌对象的构造函数(按内嵌时的声明顺序,先声明者先构造)。
然后调用本类的构造函数(析构函数的调用顺序相反)
若调用缺省构造函数(即无形参的),则内嵌对象的初始化也将调用相应的缺省构造函数。
实例:
#include<iostream>
#include<cmath>
using namespace std;
class Point
{
public:
Point(int xx = 0,int yy = 0)//构造函数
{
x = xx;
y = yy;
}
Point(Point &p);//拷贝构造函数
int getX() {return x;}
int getY() {return y;}
private:
int x,y;
};
Point::Point(Point &p)//拷贝构造函数的实现
{
x = p.x;
y = p.y;
cout << "Calling the copy constructor of Point" << endl;
}
class Line//类的组合
{
public:
Line(Point xp1, Point xp2);// 构造函数、
Line(Line &q);//拷贝构造函数
double getLen() {return len;}
private:
Point p1, p2; //Point 类的对象 p1,p2
double len;
};
//组合类的构造函数
Line::Line(Point xp1, Point xp2):p1(xp1),p2(xp2)
{
cout << "Calling constructor of Line" << endl;
double x = static_cast<double>(p1.getX() - p2.getX());
double y = static_cast<double>(p1.getY() - p2.getY());
len = sqrt(x * x + y * y);
}
//组合类的拷贝构造函数
Line::Line(Line &q):p1(q.p1),p2(q.p2)
{
cout << "Calling the copy constructor of Line" << endl;
len = q.len;
}
int main()//主函数
{
Point myp1(1,1), myp2(4,5);
Line line(myp1, myp2);
Line line2(line); //利用拷贝构造函数建立一个新对象
cout << "The length of the line is: ";
cout << line.getLen() << endl;
cout << "The length of the line2 is: ";
cout << line2.getLen() << endl;
return 0;
}
运行结果:
Point 的拷贝构造函数被调用了6次,分别是两个对象在 Line 构造函数进行函数参数形实结合时,初始化内嵌对象时,以及拷贝构造 line2 时被调用的
7、前向引用声明
类应该先声明,后使用
如果需要在某个类的声明之前,引用该类,则应进行前向引用声明
前向引用声明只为程序引入一个标识符,但具体声明在其它地方。
class B; //前向引用声明
class A
{
public:
void f(B b);
};
class B
{
public:
void g(A a);
};
8、类模板
声明及用途
template<模板参数表>
类声明
使用类模板使用户可以为类声明一种模式,使得类中的某些数据成员、某些成员函数的参数、
某些成员函数的返回值,能取任意类型(包括系统预定义的和用户自定义的)
实例:
#include<iostream>
#include<cstdlib>
using namespace std;
struct Student//结构体Student
{
int id;
float gpa;
};
template <class T> //类模板:实现对任意类型数据进行存取
class Store
{
private:
T item; //item用于存放任意类型的数据
int haveValue; //havaValue 标记 item 是否已被存入内容
public:
Store(void); //默认形式(无形参)的构造函数
T GetElem(void); //提取数据函数
void PutElem(T x); //存入数据函数
};
//以下实现个成员函数,
//注意:模板类的成员函数,若在类外实现,则必须是模板函数
//默认形式构造函数的实现
template <class T>
Store<T>::Store(void):haveValue(0){}
//提取数据函数实现
template <class T>
T Store<T>::GetElem(void)
{
//如果试图提取未初始化的数据,则终止程序
if (haveValue == 0)
{
cout << "No item present!" << endl;
exit(1);
}
return item; //返回 item 中存放的数据
}
//存入数据函数的实现
template <class T>
void Store<T>::PutElem(T x)
{
haveValue++; //将 haveValue 置为 TURE,表示 item已存入数值
item = x; //将x值存入 item
}
int main(void)
{
Student g = {1000, 23};
Store<int> S1, S2;//声明两个对象,其中数据成员 item 为 int 类型
Store<Student> S3;//声明对象,item 为 Student 类型
Store<double> D; //声明对象,item 为 double 类型
S1.PutElem(3);
S2.PutElem(-7);
cout << S1.GetElem() << " " << S2.GetElem() << endl;
S3.PutElem(g);
cout << "The student id is " << S3.GetElem().id << endl;
cout << "Retrieving object D ";
cout << D.GetElem() << endl; //由于D未初始化,终止程序
return 0;
}
运行结果: