类和对象的定义与访问
1、定义类和对象
C++中,类定义的说明语句一般形式为:
class<类名>
{
public:
公有段数据成员和成员函数;
protected:
保护段数据成员和成员函数;
private:
私有段数据成员和成员函数;
};
其中,class是定义类的关键字。“类名”是用户自定义的标识符,用于标识类型的名字。一对花括号相括说明类的成员,以分号结束类定义语句。
*注:
类成员用关键字指定不同的访问特性,决定其在类体系中或类外的可见性。
private用于声明私有成员。私有成员只能在类中可见,不能在类外或派生类中使用。
protected声明保护成员。保护成员在类和它的派生类中可见。
public声明公有成员。公有成员是类的接口,在类中和类外可见。
例:一个日期类的说明
class Date
{
public:
void SetDate(int y,int m,int d);
int IsLeapYear();
void PrintDate();
private:
int year,month,day;
};
2、访问对象成员
对象成员的访问形式与访问结构的形式相同,运算符“.”和“->”用于访问对象成员。
例:访问对象的公有成员
#include<iostream>
using namespace std;
class Tclass
{ public:
int x,y;
void print()
{ cout<<x<<","<<y; };
};
int main()
{ Tclass test;
test.x=100; //访问公有段数据成员
test.y=200;
test.print(); //调用公有段成员函数
}
3、this指针
一般来说,所有类方法都将this指针设置为调用它的对象的地址;
当参数与成员变量名相同时,如this->x = x,不能写成x = x。
构造函数和析构函数
1、构造函数
如果类中没有定义构造函数,系统将自动生成一个默认形式的构造函数,用于创建对象,默认构造函数形式:
类名::类名(){}
默认构造函数是一个空函数。
*注:
(1) 利用构造函数直接创建对象.其一般形式为:
类名 对象名[(实参表)];
这里的“类名”与构造函数名相同,“实参表”是为构造函数提供的实际参数。
(2)利用构造函数创建对象时,通过指针和new来实现。其一般语法形式为:
类名 *指针变量 = new 类名[(实参表)];
例:为类Date建立一个构造函数。
#include <iostream.h>
class Date {
public:
Date(); // 无参构造函数
Date(int y,int m,int d);
void showDate();
private:
int year, month, day;
};
Date::Date() // 构造函数的实现
{ year=0; month=0; day=0; }
Date::Date(int y,int m,int d)
{ year=y; month=m; day=d; }
inline void Date::showDate()
{ cout<<year<<"."<<month<<"."<<day<<endl; }
int main()
{
Date a_date,bDate(2014,3,25);
a_date.showDate();
b_date.showDate();
return 0;
}
2、析构函数
析构函数的 定义格式如下 ( 类外实现 ) :
类名::~类名()
{
函数语句
}若没有显式定义析构函数,则系统自动生成一个默认形式的析构函数。
系统自动生成的默认构造函数形式如下:
类名 ::~ 类名 (){}一般情况下,可以不定义析构函数
但如果类的数据成员中包含指针变量是从堆上进行存储空间分配的话,需要在析构函数中进行存储空间的回收
析构函数与构造函数名字相同,但它前面必须加一个波浪号(~)。
析构函数没有参数,也没有返回值,而且不能重载。因此在一个类中只能有一个析构函数。
当撤消对象时,编译系统会自动地调用析构函数。
复制构造函数
复制构造函数用一个已有同类对象创建新对象进行数据初始化
C++为类提供默认版本的复制构造函数
程序员可以定义用户版本的复制构造函数
语法形式
类名::类名(const 类名 & 引用名 , …);
*注:
例:复制构造函数的基本工作
class Point
{
public:
Point(float PointA_x=0, float PointA_y=0);
void Move(float New_x, float New_y);
float GetPointx();
float GetPointy();
private:
float P1_x,P1_y;
};
浅复制
在用一个对象初始化另一个对象时,只复制了数据成员,而没有复制资源,使两个对象同时指向了同一资源的复制方式称为浅复制。
即:对于复杂类型的数据成员只复制了存储地址而没有复制存储内容。
默认复制构造函数所进行的是简单数据复制。
深复制
通过一个对象初始化另一个对象时,不仅复制了数据成员,也复制了资源的复制方式称为深复制。
定义:
类名::类名([const]类名 &对象名);
类的其他成员
常成员
在类中使用关键字const说明的函数为常成员函数,常成员函数的说明格式如下:
类型说明符函数名(参数表) const;
const是函数类型的一个组成部分,因此在函数的实现部分也要带关键字const。
常成员函数不能更新对象的数据,也不能调用非const修饰的成员函数(静态成员函数、构造函数除外)。
#include<iostream>
using namespace std;
class Mclass
{ public :
int k;
const int M;
Mclass() : M(5) { }
void testFun()
{ //M++;
k++;
}
} ;
静态成员
静态数据成员在定义或说明时前面加关键字static,如:
class A
{
int n;
staticints;
};*注:
友元
构造函数 ( 形参表 ) : 对象成员1(形参表 ) , … , 对象成员n (形参表 ) ;
例:
class A
{ private:
int i ;
friend void FriendFun(A * , int) ;
public:
void MemberFun(int) ;
} ;
…
void FriendFun( A * ptr , int x )
{ ptr -> i = x ; } ;
void A:: MemberFun( int x )
{ i = x ; } ;
附:学生成绩查询
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
class student
{
string name;
int no;
int score[3];
float average;
int order;
public:
student(int id,string na,int x,int y,int z):name(na),no(id)
{
score[0]=x;
score[1]=y;
score[2]=z;
order=1,average=(score[0]+score[1]+score[2])/3;
}
student()
{
score[0]=score[1]=score[2]=0;
order=1,average=0;
}
int getNo(){return no;}
float getAverage(){return average;}
void setAverage(int avg){average=avg;}
void setOrder(int x){order=x;}
int getOrder(){return order;}
string getName(){return name;}
void setName(string name){this->name=name;}
void display();
};
void student::display()
{
cout<<name<<"\t"<<no<<"\t"<<score[0]<<"\t"<<score[1]<<"\t"<<score[2]<<"\t"<<average<<"\t"<<order<<endl;
}
bool cmp1(student stu1,student stu2)
{
if(stu1.getAverage()-stu2.getAverage()>=1e-9)return 1;
else return 0;
}
bool cmp2(student stu1,student stu2)
{
return stu1.getNo()<stu2.getNo();
}
class student_list
{
student list[60];
int n;
public:
student_list():n(0){};
void add();
void deleteStu();
void query();
void change();
void display(int flag);
void menu();
int search(int no);
void sortList();
};
void student_list::add()
{
int no,x,y,z;
string name;
system("cls");
cout<<"按学号·姓名·数学·英语·c++顺序输入学生信息,学号输入-1表示结束"<<endl;
while((cin>>no)&&no!=-1)
{
cin>>name>>x>>y>>z;
student s(no,name,x,y,z);
list[n++]=s;
sortList();
}
}
void student_list::sortList()
{
sort(list,list+n,cmp1);
int i;
for(i=0;i<n;i++)
list[i].setOrder(i+1);
}
void student_list::display(int flag)
{
if(flag)sort(list,list+n,cmp2);
else sort(list,list+n,cmp1);
cout<<"姓名"<<"\t"<<"学号"<<"\t"<<"数学"<<"\t"<<"英语"<<"\t"<<"c++"<<"\t"<<"平均成绩"<<"\t"<<"名次"<<endl;
for(int i=0;i<n;i++)
list[i].display();
}
int student_list::search(int no)
{
int i;
for(i=0;i,n;i++)
if(list[i].getNo()==no)
return -1;
}
void student_list::query()
{
int no,i;
system("cls");
cout<<"请输入要查询同学的学号,按-1结束查询";
while(cin>>no&&no!=-1)
{
i=search(no);
if(i!=-1)
{
cout<<"姓名"<<"\t"<<"学号"<<"\t"<<"数学"<<"\t"<<"英语"<<"\t"<<"c++"<<"\t"<<"平均成绩"<<"\t"<<"名次"<<endl;
list[i].display();
cout<<"请输入要查询同学的学号,按-1结束查询";
}
else
cout<<"学号输入有误,请重输,输入-1结束查询"<<endl;
}
}
void student_list::change()
{
int no,i,x,y,z;
string name;
system("cls");
cout<<"输入要修改的学生学号,按-1结束查询"<<endl;
while(cin>>no&&no!=-1)
{
i=search(no);
if(i!=0)
{
cout<<"修改后的同学的姓名·数学·英语·c++"<<endl;
cin>>name>>x>>y>>z;
student s(no,name,x,y,z);
list[i]=s;
sortList();
cout<<"请输入要修改同学的学号,按-1结束查询"<<endl;
}
else
cout<<"学号输入有误,请重输,输入-1结束查询"<<endl;
}
}
void student_list::deleteStu()
{
int no;
system("cls");
cout<<"请输入要删除同学的学号,按-1结束查询";
}
int main()
{
student s(1,"ff",66,77,88);
s.display();
cout<<s.getAverage()<<endl;
s.setName("方法");
s.display();
student_list c;
c.add();
c.display(1);
c.query();
c.display(0);
c.change();
c.deleteStu();
return 0;
}
总结:
通过这一章的学习,完成了由面向过程到面向对象的思维转变。同时也让我对设计管理系统有了一个初步的理解,即先了解所需求的功能,然后设计框架,进行分类以及接下来的数据修饰。但随着课程的逐步深入,我也感觉到了C++学习的越发困难,但我会继续努力。