一.知识点
1.类
class<类名> //类名的首字母大写
{public:
公有数据成员和成员函数;
private:
私有数据成员和成员函数;
};
注:(1)c++默认类class成员的访问为私有private,struct的为public
(2)数据成员私有化,成员函数公有化
(3)先考虑如何组织数据,再解决问题。首先定义类,再写主函数(程序从主函数开始运行) 主函数中包括对象的定义说明,对象只能通过成员使用,对象.公有成员
2.成员函数
⑴成员函数在类外定义形式 返回类型 类名::函数名(参数表)
一般在类外具体实现成员函数
例如:voidDate::SetDate(int y,int m,int d)
{ year=y;
month=m;
day=d;}
⑵简单成员函数也可以在类内定义
例如:void SetDate(int y,int m,int d)
{year=y;
month=m;
day=d;}
注:⑴在类的定义中不能对数据成员初始化
⑵类的组合:一个类的成员可以是已经定义的其他类的对象,可以是数组、类等
3.对象
⑴定义:对象是类的实例或实体,类与对象的关系,如同C++基本数据类型和该类型的变量之间的关系。
(2)格式:类名 对象名1,对象名2,…,对象名n;
(3)类对象的访问
圆点访问形式:对象名.公有成员名
指针访问形式:对象指针变量名->公有成员名
注:必须在定义了类之后,才可以定义类的对象。
4.this指针
this指针在类内使用,指明对象本身
类的成员函数如何区分不同的实例对象的数据成员?
C++为此专门设立了一个名为this的指针,用来指向不同的对象。
一个对象的this指针并不是对象本身的一部分,不会影响sizeof(对象)的结果。
需要显式引用this指针的三种情况
(1)在类的非静态成员函数中返回类对象本身或对象的引用的时候,直接使用 return *this,返回本对象的地址时,return this。
(2)当参数与成员变量名相同时,如this->x= x,不能写成x = x。
(3)避免对同一对象进行赋值操作,判断两个对象是否相同时,使用this指针。
例如:voidTclass::print()
{cout<<this->x<“ ”<<this->y<<endl;
5.函数重载
函数名相同,但参数不相同(类型不同,或者个数不同)的一组函数。
编译器根据不同参数的类型和个数产生调用匹配
函数重载用于处理不同数据类型的类似任务
例如:参数的个数不同
class Date
{public:
Date();
Date(int):
Date(int,int);
};
void f()
{Date d;//调用Date()
Date d1(2000);调用Date(int)
Date d1(2000,1);调用Date(int int)
}
6.构造函数与析构函数(重点)
构造函数与析构函数是类的特殊成员函数,应定义在公有部分
(1)构造函数名与类名相同,可以有任意类型的参数,但不能有返回类型,为对象分配空间;对数据成员赋初值;请求其他资源 构造函数可以重载
析构函数是在类名之前加 ~ 无参数没有返回类型 自动调用 释放对象释放空间,一个类中只能有一个析构函数;
(2)构造函数形式:类名::类名(参数表);
析构函数形式:类名::~类名();
(3)没有用户定义的构造函数时,系统提供缺省的构造函数
调用对应构造函数后,用户定义了构造函数后,缺省构造函数不再起作用,所以必须先定义不带参的构造函数
如果类中没有定义构造函数,系统将自动生成一个默认形式的构造函数,用于创建对象,默认构造函数形式: 类名::类名(){} 默认构造函数是一个空函数
(5)利用构造函数创建对象有以下两种方法:
①利用构造函数直接创建对象.其一般形式为:
类名 对象名[(实参表)];
这里的“类名”与构造函数名相同,“实参表”是为构造函数提供的实际参数。
② 利用构造函数创建对象时,通过指针和new来实现。其一般语法形式为:
类名 *指针变量 = new 类名[(实参表)];
new 动态申请空间申请后返回首地址 所以定一个指针变量
例如:
Date *date1=new Date(1998,4,28);
date1->showDate();
就创建了对象(*date1)
(6)构造函数的初始化列表(数据成员的初始化)
构造函数初始化成员有两种方法
A.使用构造函数的函数体进行初始化
B.使用构造函数的初始化列表进行初始化
必须用参数初始化列表对数据成员进行初始化的几种情况
①数据成员为常量
②数据成员为引用类型
③数据成员为没有无参构造函数的类的对象
(7)复制构造函数
复制构造函数有一个类类型的引用参数,用一个已有同类对象创建新对象进行数据初始化,C++为类提供默认版本的复制构造函数 包括深复制与浅复制,深复制用new申请空间
语法形式
类名 :: 类名(const 类名 & 引用名 , …);
注:(1)这里用const 保护实参对象为只读,保证所引用对象不被修改
(2)深复制构造函数必须显式定义,特点
① 定义:类名::类名([const] 类名 &对象名);
② 成员变量的处理:对复杂类型的成员变量,使用new操作符进行空间的申请,然后进行相关的复制操作
复制构造函数的特点:
① 复制构造函数名与类名相同,并且也没有返回值类型。
② 复制构造函数可写在类中,也可以写在类外。
③ 复制构造函数要求有一个类类型的引用参数。
④ 如果没有显式定义复制构造函数,系统自动生成一个默认形式的复制构造函数。
注:(1)构造函数Date::Date()与成员函数Date::SetDate()作用不同,通过SetDate,可以多次重置数据成员的值,但构造函数不能通过对象显式调用首先创建的对象最后析构
(2)对象不要定义成全局对象,不能定义在主函数之外
7.类成员的初始化的顺序:
按照数据成员在类中的声明顺序进行初始化,与初始化成员列表中出现的顺序无关,成员对象的构造函数调用次序和成员对象在类中的说明次序一致(声明顺序为:a1、b1、b2),与它们在成员初始化列表中出现的次序无关(初始化列表顺序为:b1、b2、a1)即析构函数的调用顺序相反
例如:
#include <iostream>
using namespace std;
class CmyClass
{
public:
CMyClass(int x, int y):m_y(x),m_x(m_y)
{
cout<<"m_x="<<m_x<<endl;
cout<<"m_y="<<m_y<<endl;
}
private:
int m_x,m_y;
};
int main()
{
CMyClass mc(15,10);
return 0;
}
运行结果:
m_x=-858993460
m_y=15
8.类的其他成员
(1)常成员(只读不写)用关键字const,c
常数据成员构造函数只能通过初始化列表对常数据成员进行初始化,初始化列表形式类名():数据成员(形参){赋值语句},使用const说明的数据成员称为常数据成员,const放在前面。
如果在一个类中说明了常数据成员,那么构造函数就只能通过初始化列表对该数据成员进行初始化,而任何其他函数都不能对该成员赋值。
例如:
由构造函数直接用常量初始化常数据成员
#include<iostream>
using namespace std;
class Mclass
{ public :
int k;
const int M;//说明常数据成员
Mclass() : M(5) { } //用初始式对常数据成员赋值
void testFun()
{ //M++;
k++;
}
} ;
(2)常对象
①常对象的说明形式如下:
类名const 对象名[(参数表)];
或者
const 类名 对象名[(参数表)];
②在定义常对象时必须进行初始化,而且不能被更新。
(1)C++不允许直接或间接更改常对象的数据成员。
(2)C++规定常对象只能调用它的常成员函数、静态成员函数、构造函数(具有公有访问权限)。
(3)常成员函数
常成员函数的形式 类型说明符 函数名(参数表) const;
const是函数类型的一个组成部分,因此在函数的实现部分也要带关键字const。
常成员函数不能更新对象的数据,也不能调用非const修饰的成员函数(静态成员函数、构造函数除外)
9.静态成员(static)
即类成员,不属于某个单独的对象,而是为类的所有对象所共有
(1)静态数据成员
①静态数据成员的说明
在定义或说明时前面加关键字static
如:
class A
{
int n;
static int s;
};
②静态数据成员的初始化 直接说明类以后赋初值,不能在初始化列表中赋值
③静态数据成员的访问
公有访问权限的静态成员,可以通过下面的形式进行访问
访问形式 类名::静态成员的名字
对象名.静态成员名字
对象指针->静态成员的名字
在静态成员函数内部,直接访问。
注:①在类说明中,静态数据成员的声明不是定义,因此必须在类外定义
②类定义完后,对静态成员赋初值形式 (在类外对静态成员函数赋初值)
类型 类名::静态数据成员=初始化值;
③不能在成员初始化列表中进行初始化
如果未进行初始化,则编译器自动赋初值(默认值是0)
(2)静态成员函数
仅可以访问静态成员、静态成员函数、静态数据成员,对静态成员的引用不需要用对象名。
静态成员函数没有this指针,只能对静态数据操作
定义静态成员函数的格式:
static 返回类型 静态成员函数名(参数表);
调用公有静态成员函数的格式:
类名::静态成员函数名(实参表)
对象. 静态成员函数名(实参表)
对象指针->静态成员函数名(实参表)
注:(1)静态成员函数在类外定义时不用static前缀。
(2)静态成员函数主要用来访问同一类中的静态数据成员。
(3)私有静态成员函数不能在类外部或用对象访问。
(4)成员函数中是没有this指针的。
(5)成员函数不访问类中的非静态数据成员。如有需要,只能通过对象名(或指向对象的指针)访问该对象的非静态成员。
10.友元函数(friend)
在类中,friend放在函数原型或类名之前
11.类的包含
定义一个新的类时,把另一个类 “抄”进来,即 一个类的数据成员中包含另一个类的对象
当一个类中含有已经定义的类类型成员,带参数的构造函数对数据成员初始化,须使用初始化语法形式。
构造函数 (形参表 ) : 对象成员1(形参表) , … , 对象成员n (形参表 ) ;
注:(1)出现成员对象时,该类的构造函数要包含对象成员的初始化。如果构造函数的成员初始化列表没有对成员对象初始化时,则使用成员对象的无参(缺省)构造函数。
(2)建立一个类的对象时,要先执行成员对象自己的构造函数,再执行当前类的构造函数。
有关简单对象成员初始化的问题
如何对数据成员进行初始化?
构造函数的作用
构造函数定义特点。
名字?
返回值?
参数
默认的构造函数
构造函数的重载
初始化成员列表
例如:
#include<iostream>
using namespace std;
class A
{ public:
A(intx):a(x){ }
int a;
};
class B
{ public:
B( intx, int y ) : aa(x) { b = y ; }
voidout() { cout<<"aa = "<<aa.a<<endl<<"b ="<<b<<endl ; }
private:
int b;
A aa ;
} ;
int main()
{ B objB( 3, 5 ) ;
objB.out() ;
}
二.简单例题
1.成员初始化列表与无参构造函数的使用
#include<iostream>
using namespace std;
class A{
public:
A( ){cout<<"This is A."<<endl; } //缺省构造函数
A(int i){ cout<<"This is A, and it's value = "<<i<<endl; }
};
class B{
public:
B( ){ cout<<"This isB"<<endl; } //缺省构造函数
B(inti):a2(i) { cout<<"Hello B!"<<endl;m} //采用成员初始化列表的方式,成员对象a1的形参未初始化,将成员对象a2的形参初始化为i
private:
Aa1,a2; //声明两个A类对象a1和a2
};
int main( )
{
B b1,b2(9);
return 0;
}
2. 简单的学生信息管理系统
在学生信息管理的过程中, 需要知道每个学生的姓名,学号以及考试成绩
① 可以定义一个学生类,数据成员包括name(string), number(string)
② 考试科目比较多
(1) 方法一:在类中增加新的数据成员
(2) 方法二,定义成绩类,采用类的组合解决问题
class Score
{
public:
Score(float c, float e, float m );
Score();
void show();
void modify(float c, float e, float m);
private:
float computer;
float english;
float mathematics;
};
class Student
{
private:
string name;
string stu_no;
Score score1;
public:
Student(string name1, string stu_no1, floats1, float s2, float s3):score1(s1,s2,s3){
name=name1;
stu_no=stu_no1;
}
~Student();
void modify(string name1, char *stu_no1,float s1, float s2, float s3);
void show();
};
void main()
{
Student stu1("LiMing","990201", 90, 80, 70);
stu1.show ();
cout<<endl;
stu1.modify ("ZhangHao","990202", 95, 85, 75);
stu1.show ();
}
该程序只能处理一个学生的信息。
显然,考试管理要管理若干学生的信息。
利用对象数组解决问题
Student stu[100];这是定义一个对象数组,对象数组形式 类名 数组名[下标表达式];
(1) 定义一个Student 类
该类对象所共有的属性
姓名,学号,数学成绩,英语成绩,计算机,平均成绩,学生名次
该类对象的操作
初始化一个对象(输入一个学生的相关信息)
输出每个对象的信息
修改信息
(2) 定义一个成绩表类
一个数据成员,记录班级人数
一个对象数组,记录所有同学的信息
该类的操作
构造函数,输入学生人数,并输入相应的学生信息
追加函数:补充学生信息到对象数组中,并增加学生人数;
查询:按照学生的学号进行信息的查询
修改:按照学生的学号进行信息的修改
删除某个学生:删除某个数组分量,同时学生人数减1
统计每个分数段的学生的人数
(3) 设计操作类
一个成员函数实现一个具体功能;
设确定数据成员,设计构造函数;
(4) 设计数据类
整合操作类所需要的数据、设计数据类
明确如何修饰数据成员、确定数据类的成员函数
(5) 编码调试数据类
在main函数中创建数据类对象、调用各成员函数
(6) 调试操作类
先调试最急需的成员函数;
再陆续增加成员函数
最后增加菜单函数
调试方法同数据类
设计多组测试数据,用不同的测试数据反复运行程序
注:管理信息系统开发基本步骤
了解系统要实现什么功能?增删查改
对系统功能进行分类汇总
三.心得体会
这一章学习了类和对象的有关知识,对如何开发和调试系统有了初步的皮毛的了解,先考虑如何组织数据,然后再解决问题,做系统主要分为两大部分写程序和调程序。程序主要分为两大类,数据类与操作类,数据类用于描述信息,在成员函数中肯定至少有一组get()set()函数和构造函数。操作类用于实现程序的具体功能,例如管理信息系统主要有“增删查改”四个功能。操作类中一定有数据成员,并且数据成员一定是集合类型即对象数组。调试程序用“滚雪球法”,将实际问题分解成若干个小问题,先想操作,再想数据,每定义一个类,先将他调通,再写下面的程序。
但是总是感觉最近学的迷迷糊糊的,有些概念不清楚,有些概念总是混在一起分不清,有的使用形式不清楚,总而言之,不大会定义类,写类时只能比着书上的例题或已经给出的程序敲,在定义对象后,怎么在主函数中调用类还是有点疑问,如何解决问题,这个系统要实现什么功能,怎么一步步地用代码实现功能,如何调用数据,怎么将一个个的小类最后整合在一起,完成一个系统,这些问题有的似懂非懂,有的懂了但不会运用。以前c++有不大懂的问题时还可以去问同学或者百度,但现在有的时候自己连问题都不知道怎么去描述,自己具体是哪里不明白也说不上来,怎么去学好类也不懂得方法,总而言之,最近这一章学的比较吃力,学的也不大扎实,心里有点怕。