C++ 复习篇之 类和对象(一)

来源:互联网 发布:ipad淘宝卖家 编辑:程序博客网 时间:2024/05/22 00:56

1.类和对象

类是创建对象的模板,一个类可以创建多个对象,每个对象都是类类型的一个变量;创建对象的过程也叫类的实例化每个对象都是类的一个具体实例(Instance),拥有类的成员变量和成员函数

与结构体一样,类只是一种复杂数据类型的声明,不占用内存空间。而对象是类这种数据类型的一个变量,或者说是通过类这种数据类型创建出来的一份实实在在的数据,所以占用内存空间

有些教程将类的成员变量称为类的属性Property),将类的成员函数称为类的方法Method)。在面向对象的编程语言中,经常把函数(Function)称为方法(Method)。

 

2.类的定义

类是用户自定义的类型,如果程序中要用到类,必须提前说明,或者使用已存在的类(别人写好的类、标准库中的类等),C++语法本身并不提供现成的类的名称、结构和内容。

class Student{

public:

    //成员变量

    char *name;

    int age;

    float score;

    //成员函数

    void say(){

        cout<<name<<"的年龄是"<<age<<",成绩是"<<score<<endl;

    }

};

classC++中新增的关键字,专门用来定义类。Student是类的名称;类名的首字母一般大写,以和其他的标识符区分开。{ }内部是类所包含的成员变量和成员函数,它们统称为类的成员(Member);由{ }包围起来的部分有时也称为类体,和函数体的概念类似。public也是C++ 的新增关键字,它只能用在类的定义中,表示类的成员变量或成员函数具有“公开”的访问权限。

注意在类定义的最后有一个分号;,它是类定义的一部分,表示类定义结束了,不能省略。

 

类只是一个模板(Template),编译后不占用内存空间,所以在定义类时不能对成员变量进行初始化,因为没有地方存储数据。只有在创建对象以后才会给成员变量分配内存,这个时候就可以赋值了。

 

类可以理解为一种新的数据类型,该数据类型的名称是 Student。与charintfloat等基本数据类型不同的是,Student是一种复杂数据类型,可以包含基本类型,而且还有很多基本类型中没有的特性,以后大家会见到。

 

 

3.创建对象

有了 Student 类后,就可以通过它来创建对象了,例如:

Student liLei;  //创建对象

Student是类名,liLei是对象名。这和使用基本类型定义变量的形式类似:

int a;  //定义整型变量

从这个角度考虑,我们可以把 Student 看做一种新的数据类型,把 liLei 看做一个变量。

在创建对象时,class 关键字可要可不要,但是出于习惯我们通常会省略掉 class 关键字,例如:

class Student LiLei;  //正确

Student LiLei;  //同样正确

除了创建单个对象,还可以创建对象数组:

Student allStu[100];

该语句创建了一个 allStu数组,它拥有100个元素,每个元素都是Student 类型的对象

4.访问类的数据成员

创建对象以后,可以使用点号.来访问成员变量和成员函数,这和通过结构体变量来访问它的成员类似

#include <iostream>

using namespace std;

//类通常定义在函数外面

class Student{

public:

    //类包含的变量

    char *name;

    int age;

    float score;

    //类包含的函数

    void say(){

        cout<<name<<"的年龄是   "<<age<<",成绩是"<<score<<endl;

    }

};

int main(){

    //创建对象

    Student stu;

    stu.name = "小明";

    stu.age = 15;

    stu.score = 92.5f;

    stu.say();

    return 0;

}

stu 是一个对象,占用内存空间,可以对它的成员变量赋值,也可以读取它的成员变量。

 

类通常定义在函数外面,当然也可以定义在函数内部,不过很少这样使用。

 

5.使用对象指针

C语言中经典的指针在 C++中仍然广泛使用,尤其是指向对象的指针,没有它就不能实现某些功能。

上面代码中创建的对象 stu 在栈上分配内存,需要使用&获取它的地址,例如:

Student stu;

Student *pStu = &stu;

pStu 是一个指针,它指向 Student类型的数据,也就是通过 Student创建出来的对象。

当然,你也可以在堆上创建对象,这个时候就需要使用前面讲到的new关键字,例如:

Student *pStu = new Student;

在栈上创建出来的对象都有一个名字,比如 stu使用指针指向它不是必须的。但是通过 new创建出来的对象就不一样了,它在堆上分配内存,没有名字,只能得到一个指向它的指针,所以必须使用一个指针变量来接收这个指针,否则以后再也无法找到这个对象了,更没有办法使用它。也就是说,使用 new在堆上创建出来的对象是匿名的,没法直接使用,必须要用一个指针指向它,再借助指针来访问它的成员变量或成员函数。

栈内存是程序自动管理的,不能使用 delete 删除在栈上创建的对象;堆内存由程序员管理,对象使用完毕后可以通过 delete 删除。在实际开发中,newdelete往往成对出现,以保证及时删除不再使用的对象,防止无用内存堆积。

 

有了对象指针后,可以通过箭头->来访问对象的成员变量和成员函数,这和通过结构体指针来访问它的成员类似,请看下面的示例:

#include <iostream>

using namespace std;

class Student{

public:

    char *name;

    int age;

    float score;

    void say(){

        cout<<name<<"的年龄是"<<age<<",成绩是"<<score<<endl;

    }

};

int main(){

    Student *pStu = new Student;

    pStu -> name = "小明";

    pStu -> age = 15;

    pStu -> score = 92.5f;

    pStu -> say();

    delete pStu;  //删除对象

    return 0;

}

两种创建对象的方式:一种是在栈上创建,形式和定义普通变量类似;另外一种是在堆上创建,必须要用一个指针指向它,读者要记得 delete掉不再使用的对象。

6.类的成员变量和成员函数

类可以看做是一种数据类型,它类似于普通的数据类型,但是又有别于普通的数据类型。类这种数据类型是一个包含成员变量和成员函数的集合。

 

类的成员变量和普通变量一样,也有数据类型和名称,占用固定长度的内存。但是,在定义类的时候不能对成员变量赋值,因为类只是一种数据类型或者说是一种模板,本身不占用内存空间,而变量的值则需要内存来存储。

 

类的成员函数也和普通函数一样,都有返回值和参数列表,它与一般函数的区别是:成员函数是一个类的成员,出现在类体中,它的作用范围由类来决定;而普通函数是独立的,作用范围是全局的,或位于某个命名空间内。

 

class Student{

public:

    //成员变量

    char *name;

    int age;

    float score;

    //成员函数

    void say(){

        cout<<name<<"的年龄是"<<age<<",成绩是"<<score<<endl;

    }

};

class Student{

public:

    //成员变量

    char *name;

    int age;

    float score;

    //成员函数

    void say();  //函数声明

};

//函数定义

void Student::say(){

    cout<<name<<"的年龄是"<<age<<",成绩是"<<score<<endl;

}

 

在类体中直接定义函数时,不需要在函数名前面加上类名,因为函数属于哪一个类是不言而喻的。

但当成员函数定义在类外时,就必须在函数名前面加上类名予以限定::被称为域解析符(也称作用域运算符或作用域限定符),用来连接类名和函数名,指明当前函数属于哪个类。

成员函数必须先在类体中作原型声明,然后在类外定义,也就是说类体的位置应在函数定义之前

 

6.inline成员函数

在类体中和类体外定义成员函数是有区别的:在类体中定义的成员函数会自动成为内联函数,在类体外定义的不会。当然,在类体内部定义的函数也可以加 inline关键字,但这是多余的,因为类体内部定义的函数默认就是内联函数。

当然,如果你的函数比较短小,希望定义为内联函数,那也没有什么不妥的。

如果你既希望将函数定义在类体外部,又希望它是内联函数,那么可以在定义函数时加 inline关键字。当然你也可以在函数声明处加 inline,不过这样做没有效果,编译器会忽略函数声明处的inline

class Student{

public:

    char *name;

    int age;

    float score;

    void say();  //内联函数声明,可以增加 inline关键字,但编译器会忽略

};

//函数定义

inline void Student::say(){

    cout<<name<<"的年龄是"<<age<<",成绩是"<<score<<endl;

}

这种在类体外定义 inline 函数的方式,必须将类的定义和成员函数的定义都放在同一个头文件中(或者同一个源文件中),否则编译时无法进行嵌入(将函数代码的嵌入到函数调用出)

虽然 C++ 支持将内联函数定义在类的外部,但强烈建议将函数定义在类的内部,这样它会自动成为内联函数,何必费力不讨好地将它定义在类的外部呢,这样并没有任何优势。

 

7.访问权限

C++通过 publicprotectedprivate三个关键字来控制成员变量和成员函数的访问权限,它们分别表示公有的、受保护的、私有的,被称为成员访问限定符。所谓访问权限,就是你能不能使用该类中的成员

JavaC# 程序员注意,C++ 中的 publicprivateprotected只能修饰类的成员,不能修饰类C++中的类没有共有私有之分

类的内部(定义类的代码内部),无论成员被声明为 publicprotected还是 private都是可以互相访问的,没有访问权限的限制

 

 

 

 

 

   类的声明和成员函数的定义都是类定义的一部分,在实际开发中,我们通常将类的声明放在头文件中,而将成员函数的定义放在源文件中。

    类中的成员变量 m_namem_agem_ score被设置成 private属性,在类的外部不能通过对象访问。也就是说,私有成员变量和成员函数只能在类内部使用,在类外都是无效的。

    成员函数 setname()setage()setscore()被设置为 public属性,是公有的,可以通过对象访问。

    private 后面的成员都是私有的,直到有public 出现才会变成共有的;public之后再无其他限定符,所以 public后面的成员都是共有的。

成员变量大都以m_开头,这是约定成俗的写法,不是语法规定的内容。以m_开头既可以一眼看出这是成员变量,又可以和成员函数中的形参名字区分开。

 

 

setname()为例,如果将成员变量m_name的名字修改为name,那么setname() 的形参就不能再叫name了,得换成诸如name1_name这样没有明显含义的名字,否则name=name;这样的语句就是给形参name赋值,而不是给成员变量name赋值。

 

因为三个成员变量都是私有的,不能通过对象直接访问,所以必须借助三个 public属性的成员函数来修改它们的值。下面的代码是错误的:

Student stu;

//m_namem_agem_score是私有成员变量,不能在类外部通过对象访问

stu.m_name = "小明";

stu.m_age = 15;

stu.m_score = 92.5f;

stu.show();

 

private 关键字的作用在于更好地隐藏类的内部实现,该向外暴露的接口(能通过对象访问的成员)都声明为 public不希望外部知道、或者只在类内部使用的、或者对外部没有影响的成员,都建议声明为 private

 

根据C++软件设计规范,实际项目开发中的成员变量以及只在类内部使用的成员函数(只被成员函数调用的成员函数)都建议声明为 private而只将允许通过对象调用的成员函数声明为 public

 

8.privatepublic的更多说明

对声明为 private的成员和声明为 public的成员的次序任意,既可以先出现 private部分,也可以先出现 public部分。如果既不写 private也不写 public,就默认为private

 

在一个类体中,privatepublic 可以分别出现多次。每个部分的有效范围到出现另一个访问限定符或类体结束时(最后一个右花括号)为止。但是为了使程序清晰,应该养成这样的习惯,使每一种成员访问限定符在类定义体中只出现一次。

 

 

将成员变量都声明为 private,如何给它们赋值呢,又如何读取它们的值呢?

 

我们可以额外添加两个 public属性的成员函数一个用来设置成员变量的值,一个用来修改成员变量的值。上面的代码中,setname()setage()setscore()函数就用来设置成员变量的值;如果希望获取成员变量的值,可以再添加三个函数 getname()getage()getscore()

给成员变量赋值的函数通常称为set 函数,它的名字通常以set开头,后跟成员变量的名字;读取成员变量的值的函数通常称为 get 函数,它的名字通常以get开头,后跟成员变量的名字。

除了 set 函数和 get 函数,在创建对象时还可以调用构造函数来初始化各个成员变量不过构造函数只能给成员变量赋值一次以后再修改还得借助 set 函数。

这种将成员变量声明为 private、将部分成员函数声明为public 的做法体现了类的封装性。所谓封装,是指尽量隐藏类的内部实现,只向用户提供有用的成员函数。

 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

原创粉丝点击