16 类的声明、对象的定义及使用

1 类的声明

类是创建对象的模板,一个类可以创建多个对象,每个对象都是类类型的一个变量;创建对象的过程也叫类的实例化。每个对象都是类的一个具体实例(Instance),拥有类的成员变量(属性)和成员函数(方法)。也就是说,需要先声明一个类,才能定义对应的对象。

类的声明格式如下:

class 类名{
    private:
        成员变量和成员函数
    protected:
        成员变量和成员函数
    public:
        成员变量和成员函数
};

其中, class 是定义类的关键字, publicprotectedprivate 三个关键字是用来控制成员变量和成员函数的访问权限的。这三个关键字的用法,将在 “封装” 章节具体讲解,现在,我们只用 public 关键字。

请不要忘记最后的分号

让我们看一个学生类的例子:

class Student {
public:
    string name;
    int age;
    int score;

    void say() {
        cout << "我是" << name << ",我今年" << age << "岁了,我的成绩是" << score << "分。" << endl;
    }
};

以上代码,声明了一个叫做 Student 的类,类的名字一般使用大驼峰命名法,即所有单词的首字母大写。类名后 {} 中的内容被称为 “类体” 。

类的成员函数除了可以直接定义在类体中,还可以仅在类体中存放函数原型,然后在类体外,给出函数的具体定义。此时,定义函数时,需要使用作用域运算符 :: 说明现在定义的函数属于哪个类。

class Student {
public:
    string name;
    int age;
    int score;

    void say();
};

void Student::say() {
    cout << "我是" << name << ",我今年" << age << "岁了,我的成绩是" << score << "分。" << endl;
}

定义在类体内的成员函数,默认是内联函数(inline);而定义在类体外的成员函数,默认不是内联函数,除非显式使用 inline 关键字。

class Student {
public:
    string name;
    int age;
    int score;

    void say();
};

inline void Student::say() {
    cout << "我是" << name << ",我今年" << age << "岁了,我的成绩是" << score << "分。" << endl;
}

2 对象的定义

  1. 先声明类,再定义对象。
class Student {
public:
    string name;
    int age;
    int score;

    void say() {
        cout << "我是" << name << ",我今年" << age << "岁了,我的成绩是" << score << "分。" << endl;
    }
};
……
Student stu1;
  1. 声明类的同时定义对象。
class Student {
public:
    string name;
    int age;
    int score;

    void say() {
        cout << "我是" << name << ",我今年" << age << "岁了,我的成绩是" << score << "分。" << endl;
    }
}stu1;

3 访问对象成员

  1. 通过 对象名 访问对象成员,需要使用点运算符 .。语法为:对象名.成员名
  2. 通过 指针 访问对象成员,需要使用箭头运算符 ->。语法为:指针名->成员名
  3. 通过 引用 访问对象成员,需要使用点运算符 .。语法为:引用名.成员名

示例:

#include<iostream>

using namespace std;

class Student {
public:
    string name;
    int age;
    int score;

    void say();
};

void Student::say() {
    cout << "我是" << name << ",我今年" << age << "岁了,我的成绩是" << score << "分。" << endl;
}

int main() {
    Student stu1;
    stu1.name = "张三";
    stu1.age = 16;
    stu1.score = 90;

    cout << "学生姓名:" << stu1.name << endl;
    stu1.say();

    Student *stu_ptr = &stu1;
    stu_ptr->name = "李四";
    cout << "学生姓名:" << stu_ptr->name << endl;
    stu_ptr->say();

    Student &s = stu1;
    s.name = "王五";
    cout << "学生姓名:" << s.name << endl;
    s.say();

    return 0;
}

4 对象互相赋值

使用赋值号 = 连接两个对象,相对于对象的成员变量一一赋值,而不是让它们指向相同的内存地址。

5 对象作为函数参数

类作为一种数据类型,当然可以作为函数参数使用。但在 C++ 中,直接使用类做参数类型的话,函数中得到的对象,并不是传入的对象本身,而是原对象的属性一一复制后的新对象。

#include<iostream>

using namespace std;

class Student {
public:
    string name;
    int age;
    int score;

    void say() {
        cout << "我是" << name << ",我今年" << age << "岁了,我的成绩是" << score << "分。" << endl;
    }
};

void show(Student s){
    cout << "s的地址:" << &s << endl;
    s.say();
}

int main() {
    Student stu1;
    stu1.name = "张三";
    stu1.age = 16;
    stu1.score = 85;
    cout << "stu1的地址:" << &stu1 << endl;
    show(stu1);
    return 0;
}

运行结果:
stu1的地址:0x6addbffac0
s的地址:0x6addbffb20
我是张三,我今年16岁了,我的成绩是85分。

stu1s 的内存地址不同,因此它们不是同一个对象。这有一个好处,我们在这个函数中进行的操作,不会影响到原本的对象。但这需要开辟新的内存空间,初始化一个新的对象,而这个对象生命周期仅仅到这个函数结束,这个内存空间又需要释放。因此,这样的函数,运行效率会很差。

所以,大多数情况下,我们应该用 “引用” 或 “指针” 来作为函数参数,将已有对象本身引入函数

将上面例子中,show 函数改成下面这样:

void show(Student &s){
    cout << "s的地址:" << &s << endl;
    s.say();
}

运行结果:
stu1的地址:0x54d7fffbe0
s的地址:0x54d7fffbe0
我是张三,我今年16岁了,我的成绩是85分。

此时,stu1s 是同一个对象,我们在函数内对 s 进行的操作,就是对 stu1 进行的操作。

大家需要根据我们要实现的具体功能,来确定使用那种形式。