类和对象的学习总结

本章内容包括:

First:知识点

一、类和对象的定义与访问

1、定义类和对象

2、访问对象成员

3、this指针

二、构造函数和析构函数

1、简单构造函数和析构函数

2、带参数的构造函数

3、重载构造函数

4、复制构造函数

三、类的其他成员

1、常成员

2、静态成员

3、友员

四、类的包含

一、类和对象的定义与访问

1、定义类和对象

(1)类是对具有相同属性和行为的一组对象的抽象与统一描述。是用户自定义的数据类型
(2)类的定义包括行为和属性两个部分。

(3) 属性以数据表示,行为通过函数实现。

(4)C++类定义的格式: 

class  类名
{
   public:
           公有数据成员和成员函数;
   protected:
           保护数据成员和成员函数;
   private: 
           私有数据成员和成员函数;
}
;//分号不可省略

   各成员函数的实现;

2、访问对象成员

访问控制:

类的访问属性有:
      ● Public
      ● Protected
      ● Private

  各种访问方式的功能如下表:

类成员访问控制表:

访问控制含义属性
public公有成员类的外部接口
protectd保护成员仅允许本类成元函数及派生类成员函数访问
private私有成员仅允许本类成员函数访问

成员函数

(1)类的成员函数是实现类的行为属性的成员。

(2)一般将成员函数声明为函数原型,在类外具体实现成员函数。

成员函数的定义 

返回值类型  类名::成员函数名(参数表)
{
          函数体

对象

(1)对象是类的实例或实体。

(2)类与对象的关系,如同C++基本数据类型和该类型的变量之间的关系。 

对象的定义

格式如下: 

类名  对象名1,对象名2,…,对象名n;

类成员的访问 

对象成员的访问包括:
(1)圆点访问形式:对象名.公有成员

(2)指针访问形式:对象指针变量名->公有成员

内联函数 

(1)内联函数作用:减少频繁调用小子程序的运行的时间开销

(2)内联函数机制:编译器在编译时,将内联函数的调用以相应代码代替

(3)内联函数声明:inline  函数原型

成员函数的类内实现(内联函数) 

class Coord{
    public:
        void setCoord(int a,int b)
        { x=a; y=b;}
        int getx()
        { return x;}
        int gety()
        { retrun y;}
   private:
        int x,y;

   };

成员函数可以重载  

(1)函数重载:函数名相同,但参数不相同((1)类型不同,(2)个数不同)的一组函数。
 (2)编译器根据不同参数的类型和个数产生调用匹配

 (3)函数重载用于处理不同数据类型的类似任务

3、this指针

(1)用类去定义对象时,系统会为每一个对象分配存储空间。如果一个类包括了数据和函数,要分别为数据和函数的代码分配           存储空间。按理说,如果用同一个类定义了10个对象,那么就需要分别为10个对象的数据和函数代码分配存储单元

(2) 类的成员函数如何区分不同的实例对象的数据成员呢?
    ① C++为此专门设立了一个名为this的指针,用来指向不同的对象。

    ②一个对象的this指针并不是对象本身的一部分,不会影响sizeof(对象)的结果。

(3)需要显式引用this指针的三种情况:

在类的非静态成员函数中返回类对象本身或对象的引用的时候,直接使用 return *this,返回本对象的地址时,return this。
②当参数与成员变量名相同时,如this->x = x,不能写成x = x。

③ 避免对同一对象进行赋值操作,判断两个对象是否相同时,使用this指针。

二、构造函数和析构函数

1、简单构造函数和析构函数

构造函数:

(1)构造函数是用于创建对象的特殊成员函数,当创建对象时,系统自动调用构造函数
(2) 构造函数的作用:为对象分配空间;对数据成员赋初值;请求其他资源
(3)没有用户定义的构造函数时,系统提供缺省版本的构造函数
(4)构造函数名与类名相同:类名
(5)构造函数可以重载

(6)构造函数可以有任意类型的参数,但没有返回类型

(7)默认构造函数

①如果类中没有定义构造函数,系统将自动生成一个默认形式的构造函数,用于创建对象,默认构造函数形式: 
类名::类名(){} 

②默认构造函数是一个空函数

(8)通常,利用构造函数创建对象有以下两种方法:
 利用构造函数直接创建对象.其一般形式为:
     类名 对象名[(实参表)];
     这里的“类名”与构造函数名相同,“实参表”是为构造函数提供的实际参数。 
利用构造函数创建对象时,通过指针和new来实现。其一般语法形式为:
     类名 *指针变量 = new 类名[(实参表)];
     例如:
      Date *date1=new Date(1998,4,28);就创建了对象(*date1)。
(9)构造函数的初始化列表(数据成员的初始化)
构造函数初始化成员有两种方法:
使用构造函数的函数体进行初始化 
使用构造函数的初始化列表进行初始化:
  格式:
  funname(参数列表):初始化列表
  {  函数体,可以是空函数体  } 
  初始化列表的形式: 

  成员名1(形参名1),成员名2(形参名2),成员名n(形参名n) 

(10)构造函数的调用:在生成对象时调用构造函数。

析构函数:

(1)析构函数是用于取消对象的成员函数,当一个对象作用域结束时,系统自动调用析构函数
(2)析构函数的作用是进行对象消亡时的清理工作
(3)没有用户定义析构函数时,系统提供缺省版本的析构函数
(4)析构函数名为: ~ 类名,析构函数与构造函数名字相同,但它前面必须加一个波浪号(~);

(5) 析构函数没有参数,也没有返回值,而且不能重载。因此在一个类中只能有一个析构函数;

(6)对象生存期结束时,需要做清理工作,比如:释放成员(指针)所占有的存储空间,析构函数可以完成上述工作。

(7)析构函数自动调用(隐式调用),当撤消对象时,编译系统会自动地调用析构函数。 

(8)定义格式如下(类外实现): 

类名::~类名()
{
       函数语句

}

(8)默认析构函数 

若没有显式定义析构函数,则系统自动生成一个默认形式的析构函数。
系统自动生成的默认构造函数形式如下: 

类名::~类名(){}

4、复制构造函数

(1)复制构造函数用一个已有同类对象创建新对象进行数据初始化,C++为类提供默认版本的复制构造函数,程序员可以定义           用户版本的复制构造函数 : 语法形式:

类名 :: 类名(const  类名  &  引用名  ,  …);//const的作用:保护实参对象只读

(2)复制构造函数的特点: 

A 、复制构造函数名与类名相同,并且也没有返回值类型。

 B、复制构造函数可写在类中,也可以写在类外。

C 、复制构造函数要求有一个类类型的引用参数。

 D、如果没有显式定义复制构造函数,系统自动生成一个默认形式的复制构造函数

(3)复制构造函数的调用 

A、声明语句中用类的一个已知对象初始化该类的另一个对象时。 
B、当对象作为一个函数实参传递给函数的形参时,需要将实参对象去初始化形参对象时,需要调用复制构造函数。 

C、当对象是函数的返回值时,由于需要生成一个临时对象作为函数返回结果,系统需要将临时对象的值初始化另一个对象,需        要调用复制构造函数。

(4)浅复制与深复制 

关于浅复制:
●在用一个对象初始化另一个对象时,只复制了数据成员,而没有复制资源,使两个对象同时指向了同一资源的复制方式称为浅复制。
即:对于复杂类型的数据成员只复制了存储地址而没有复制存储内容

●默认复制构造函数所进行的是简单数据复制,即浅复制 

关于深复制:
●通过一个对象初始化另一个对象时,不仅复制了数据成员,也复制了资源的复制方式称为深复制。 

●自定义复制构造函数所进行的复制是浅复制。 

●定义支持深复制的复制构造函数:深复制构造函数必须显式定义

●深复制构造函数的特点
① 定义:类名::类名([const] 类名 &对象名);

②成员变量的处理:对复杂类型的成员变量,使用new操作符进行空间的申请,然后进行相关的复制操作

三、类的其他成员

类定义中除了一般指定访问权限的成员,还可以定义各种特殊用途的成员:常成员、静态成员、友元。

常成员 

1、常成员

(1)常数据成员是指数据成员在实例化被初始化后,其值不能改变。

(2)在类的成员函数说明后面可以加const关键字,则该成员函数成为常量成员函数

 (3)常数据成员
      ① 使用const说明的数据成员称为常数据成员。

      ② 如果在一个类中说明了常数据成员,那么构造函数就只能通过初始化列表对该数据成员进行初始化,而任何其他函数都不能对该成员赋值。 

(4)常对象

  ①如果在说明对象时用const修饰,则被说明的对象为常对象。
  ② 常对象的说明形式如下:
      类名 const 对象名[(参数表)];
  或者
      const  类名 对象名[(参数表)];
  在定义常对象时必须进行初始化,而且不能被更新。  

(5)常成员函数

  ①在类中使用关键字const说明的函数为常成员函数,常成员函数的说明格式如下:

类型说明符 函数名(参数表) const;//const是函数类型的一个组成部分,因此在函数的实现部分也要带关键字const。 

  ② 常成员函数不能更新对象的数据,也不能调用非const修饰的成员函数(静态成员函数、构造函数除外)

2、静态成员

(1)类成员冠以static声明时,称为静态成员。 
(2) 静态数据成员为同类对象共享。
(3) 静态成员函数与静态数据成员协同操作。  

(4)静态成员函数

  A、静态成员不属于某一个单独的对象,而是为类的所有对象所共有

  B、静态成员函数的作用不是为了对象之间的沟通,而是为了能处理静态数据成员: 保证在不依赖于某个对象的情况下,访问静          态数据成员

  C、除静态数据成员以外,一个类还可以有静态成员函数。

  D、静态函数仅可以访问静态成员,或是静态成员函数或是静态数据成员。

  E、静态成员函数和静态数据成员一样,它们都属于类的静态成员,它们都不是对象成员。因此,对静态成员的引用不需要用对        象名。

  F、静态成员函数没有this指针,只能对静态数据操作

  G、定义静态成员函数的格式如下:

    static 返回类型 静态成员函数名(参数表);

  H、与静态数据成员类似,调用公有静态成员函数的一般格式有如下几种:

   类名::静态成员函数名(实参表)
   对象. 静态成员函数名(实参表)
   对象指针->静态成员函数名(实参表)

(5)静态数据成员在定义或说明时前面加关键字static

(6)对于类的普通数据成员,每一个对象都各自拥有一个副本。(分配不同的存储空间)。对于静态数据成员,每个类只拥有一个副本。(在静态存储区分配一个存储空间,对所有对象都是可见的)

(7)公有访问权限的静态成员,可以通过下面的形式进行访问

类名::静态成员的名字

对象名.静态成员名字

对象指针->静态成员的名字

在静态成员函数内部,直接访问。

(8)静态数据成员声明及初始化

 ①在类外进行静态数据成员的声明

    类型 类名::静态数据成员[=初始化值];   //必须进行声明

 ②不能在成员初始化列表中进行初始化,如果未进行初始化,则编译器自动赋初值(默认值是0),初始化时不能使用访问权限。

3、友员

友元函数

(1)如果在本类 A 以外的其他地方定义了一个函数 函数 B ),这个函数可以是不属于任何类的非成员函数,也可以是其他类的成员函数,
(2)在类体中用 friend 对其 函数 B 进行声明,此函数就称为本类 A 的友元函数。
(3)友元函数 函数 B 可以访问这个类 A 中的私有成员
四、类的包含

(1)类的包含是程序设计中一种软件重用技术。即定义一个新的类时,通过编译器把另一个类 “抄”进来。 

(2)当一个类中含有已经定义的类类型成员,带参数的构造函数对数据成员初始化,须使用初始化语法形式。

         构造函数 ( 形参表 ) : 对象成员1(形参表 ) , … , 对象成员n (形参表 ) ; 

(3)对象成员的初始化

 A、出现成员对象时,该类的构造函数要包含对象成员的初始化。如果构造函数的成员初始化列表没有对成员对象初始化时,则使用成员对象的无参(缺省)构造函数。

 B、建立一个类的对象时,要先执行成员对象自己的构造函数,再执行当前类的构造函数。

C、成员对象的构造函数调用次序和成员对象在类中的说明次序一致(声明顺序为:a1、b1、b2),与它们在成员初始化列表中出现的次序无关(初始化列表顺序为:b1、b2、a1)。

D、析构函数的调用顺序相反

(4)对象数组

A、所谓对象数组是指每一数组元素都是对象的数组。定义一个一维对象数组的格式如下:

        类名 数组名[下标表达式]; 

B、对象数组的初始化

当对象数组所属的类中包含带参的构造函数,可用初始化列表完成对象数组的初始化。

当对象数组所属的类中包含无参的构造函数,也可以先定义,再给每个数组元素赋值

当对象数组所属的类中包含单个参数的构造函数,可简写。

C、成员对象数组的初始化

成员对象的初始化可在构造函数初始化列表中进行,推想对于成员对象数组的初始化,也可以在本类构造函数使用初始化列表

Second:感悟总结

1、类的成员可以是其他类的对象,但不能以类自身的对象作为本类的成员,而类自身的指针和引用可以作为类的成员。
2、类定义必须以分号“;”结束。
3、类与结构体的区别:没有明确指定类成员的访问权限时,C++结构体的成员是公有的,而类的成员是私有的。

4、必须在定义了类之后,才可以定义类的对象。
5、C++中,类的名字就是用户自定义的类型的名字。可以象使用基本类型那样来使用它。
6、类定义和使用时应注意:
(1)在类的定义中不能对数据成员进行初始化。
(2)类的任何成员都必须指定访问属性,一般将数据成员定义为私有成员或保护成员,将成员函数定义为公有成员。
(3)类中的数据成员可以是C++语法规定的任意数据类型。
(4)类的成员可以是其他类的对象,称为类的组合。但不能以类自身的对象作为本类的成员。
(5)类定义必须以分号“;”结束
(6)class与struct的不同:
class中,成员缺省情况是private。
struct中,成员缺省情况是public。
7、内联函数仅在函数原型作一次声明。适用于只有1 ~ 5行的小函数,不能含有复杂结构控制语句 ,不能递归调用。
8、必须使用参数初始化列表对数据成员进行初始化的几种情况
(1)数据成员为常量
(2)数据成员为引用类型
(3)数据成员为没有无参构造函数的类的对象
9、类成员的初始化的顺序:按照数据成员在类中的声明顺序进行初始化,与初始化成员列表中出现的顺序无关
10、构造函数一般被定义为公有成员。
11、一般情况下,可以不定义析构函数
12、如果类的数据成员中包含指针变量是从堆上进行存储空间分配的话,需要在析构函数中进行存储空间的回收
13、不能在成员函数中修改常数据成员
14、不能在成员函数中修改常数据成员
15、C++不允许直接或间接更改常对象的数据成员。
16、C++规定常对象只能调用它的常成员函数、静态成员函数、构造函数(具有公有访问权限)。
说明:
17、静态成员函数在类外定义时不用static前缀。
18、静态成员函数主要用来访问同一类中的静态数据成员。
19私有静态成员函数不能在类外部或用对象访问。

20、可以在建立对象之前处理静态数据成员。

21、编译系统将静态成员函数限定为内部连接(在其他文件中不可见)。

22、静态成员函数中是没有this指针的。
23、静态成员函数不访问类中的非静态数据成员。如有需要,只能通过对象名(或指向对象的指针)访问该对象的非静态成员。
24、无法通过初始化成员列表对对象数组进行初始化
25、管理信息系统开发基本步骤
1了解系统要实现什么功能?
2对系统功能进行分类汇总
3设计操作类
(1)一个成员函数实现一个具体功能;
(2)设确定数据成员,设计构造函数;
4设计数据类
5整合操作类所需要的数据、设计数据类

(1) 明确如何修饰数据成员、确定数据类的成员函数

1编码调试数据类
(1)在main函数中创建数据类对象、调用各成员函数
2调试操作类
(1)先调试最急需的成员函数;
(2)再陆续增加成员函数
(3)最后增加菜单函数
(4)调试方法同数据类

(5)设计多组测试数据,用不同的测试数据反复运行程序

26、至少写两个构造函数,至少一个无参构造函数。

27、组合对象的初始化方法:先初始化被包含的对象成员,再初始化本身的数据成员。

28、作为整体出现的数据可以新定义一个类。

29、无法通过初始化成员列表对对象数组进行初始化。

30、“滚雪球法”:每定义一个类,增加一个功能要先调通再进行下一步增加另一个功能。

31、一开始调程序要尽量简化。

32、get函数的作用是在主函数中得到函数值,cout输出。

33、数据类中至少要包括:get函数,set函数,构造函数,显示函数。

34、函数返回类型要和数据成员一致。

35、实参和形参的顺序要一致。

36、各个函数都要进行测试。

37、操作类:

(1)操作类中的数据成员一般成集体出现。

(2)一定有数据成员,数据成员一定是集合类型(对象数组)。

(3)辅助数据成员初始化。

(4)成员名要有意义,写两个单词时第二个单词首字母大写。

(5)先写最根本的函数。

(6)/*       */注释多条语句。

(7)慢慢分析理出数据。

Third:例题

学生信息处理:

#include<bits/stdc++.h>
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(float avg){average=avg;}
    void setOrder(int x){order=x;}
    int getOrder(){return order;}
    void setScore(float a,float b,float c){
    score[0]=a,score[1]=b,score[2]=c;}
    string getName(){return name;}
    void setName(string name){this->name=name;}
    void display();
};






void Student::display()
   {
       cout<<no<<"\t"<<name<<"\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 StudentOperation
   {
       Student list[90];
       int n;
       public:
       StudentOperation():n(0){};
       void add();
       void display(int flag);
       void sorts();
       int search(int no);//判断学生表中是否有这个学生
       void query();
       void deletes();
       void changeName();
       void changeScore();
   };






   void StudentOperation::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;
       }
   }






    void StudentOperation::sorts()
    {
        sort(list,list+n,cmp1);//sort(list,list+n,cmp2);
        for(int i=0;i<n;i++)
        list[i].setOrder(i+1);
    }






    void StudentOperation::display(int flag)
    {if(flag==1)
    sort(list,list+n,cmp1);//按平均成绩排序
        else sort(list,list+n,cmp2);//按学号排序
        cout<<"学号"<<"\t"<<"姓名"<<"\t"<<"数学"<<"\t"<<"英语"<<"\t"<<"c++"<<"\t"<<"平均成绩"<<endl;
        for(int i=0;i<n;i++)
        list[i].display();
    }






int StudentOperation::search(int no)
{
for(int i=0;i<n;i++)
if(list[i].getNo()==no)return i;
else return -1;
}






void StudentOperation::query()
{int no;int flag=0;
    cout<<"请输入要查询学生的学号,按-1结束查询:"<<endl;
    while(cin>>no&&no!=-1)
    {
    if(search(no)!=-1)//有这个人
    {cout<<"学号"<<"\t"<<"姓名"<<"\t"<<"数学"<<"\t"<<"英语"<<"\t"<<"c++"<<"平均成绩"<<endl;
   list[search(no)].display(); }
    else cout<<"学号输入有误!"<<endl;


    }
    }








void StudentOperation::changeName()
{cout<<"请输入要修改的学生的学号及修改后的姓名,按-1结束修改:"<<endl;
    int no;
    string na;
    while(cin>>no&&no!=-1)
    {if(search(no)!=-1)
        {cin>>na;
        for(int i=0;i<n;i++)
        {
            if(list[i].getNo()==no)
          {list[i].setName(na);
    cout<<"学号"<<"\t"<<"姓名"<<"\t"<<"数学"<<"\t"<<"英语"<<"\t"<<"c++"<<"平均成绩"<<endl;
    list[i].display();}}
    }
}}






void StudentOperation::changeScore()
{cout<<"请输入要修改的学生的学号及数学、英语、c++的成绩,按-1结束修改:"<<endl;
    int no;
    float a,b,c;
    while(cin>>no&&no!=-1)
    {cin>>a>>b>>c;
    for(int i=0;i<n;i++)
    {
        if(list[i].getNo()==no)
        {list[i].setScore(a,b,c);
        list[i].setAverage((a+b+c)/3);
      cout<<"学号"<<"\t"<<"姓名"<<"\t"<<"数学"<<"\t"<<"英语"<<"\t"<<"c++"<<"平均成绩"<<endl;
    list[i].display();  }
    }}}






    void StudentOperation::deletes()
    {
        int no;
        cout<<"请输入您想删除的学生的学号,按-1结束删除:"<<endl;
        while(cin>>no&&no!=-1)
        {
            int i=search(no);
            list[i].setAverage(0);
            list[i].setScore(0,0,0);
            list[i].setOrder(-1);
            n-=-1;
            sorts();
          cout<<"学号"<<"\t"<<"姓名"<<"\t"<<"数学"<<"\t"<<"英语"<<"\t"<<"c++"<<endl;
    list[i].display();
        }
    }






int main()
{Student s(20171793,"孔藤",66,77,88);
Student m;
cout<<s.getNo()<<endl;
cout<<s.getAverage()<<endl;
cout<<s.getOrder()<<endl;
cout<<s.getName()<<endl;
s.display();
s.setName("方法");
s.display();
s.setAverage(100);
s.display();
s.setOrder(1);
s.display();
m.display();
StudentOperation c;
c.add();
c.display(1);
c.query();
c.changeName();
c.changeScore();
c.deletes();
return 0;
}

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Famiglistimott

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值