C++:类的定义与声明、类对象应用

1. 类的声明(Class Declaration)

类的声明是向编译器介绍类的名称以及类包含哪些成员(数据成员和成员函数),但此时并不定义这些成员函数的具体实现。

语法格式:

class ClassName {
    public:
        // 公有成员(数据成员或成员函数)声明
        DataType memberVariable;
        ReturnType memberFunction(Parameters);
    protected:
        // 保护成员声明
        DataType protectedVariable;
        ReturnType protectedFunction(Parameters);
    private:
        // 私有成员声明
        DataType privateVariable;
        ReturnType privateFunction(Parameters);
};

例如,声明一个简单的表示二维点的类:

class Point {
    public:
        int x;
        int y;
        void printPoint();
};

在这个声明中,Point是类名,x和y是公有数据成员,表示点的横纵坐标,printPoint是公有成员函数,用于打印点的坐标。但是这里并没有给出printPoint函数的具体实现。

2. 类的定义(Class Definition)

类的定义包含了类的声明以及类成员函数的具体实现。

对于上面声明的Point类,可以这样定义其成员函数:

// 类外定义成员函数
void Point::printPoint() {
    std::cout << "(" << x << ", " << y << ")" << std::cout;
}

如果要在类内部直接定义成员函数,语法如下(以重新定义Point类为例):

class Point {
    public:
        int x;
        int y;
        // 在类内部直接定义成员函数
        void printPoint() {
            std::cout << "(" << x << ", " << y << ")" << std::cout;
        }
};

类的定义可以将类的声明和部分或全部成员函数的定义放在一起,也可以先声明类,然后在类外定义成员函数。类外定义成员函数时,需要使用类名::函数名的形式来表明这个函数是属于该类的。这种方式有助于组织代码结构,提高代码的可读性和可维护性。

类是C++中的一种用户自定义类型,通过类的定义和声明,可以创建具有特定属性(数据成员)和行为(成员函数)的对象,从而实现面向对象编程中的封装、继承和多态等特性。

3. 类的成员(Class Members)

数据成员(Data Members)

数据成员用于存储类对象的属性信息。它们可以是各种基本数据类型(如int、double、char等),也可以是其他自定义类型(如其他类类型、结构体类型、枚举类型等)。

例如,在一个表示矩形的类Rectangle中:

class Rectangle {
    public:
        int length;
        int width;
};

这里的length和width就是Rectangle类的数据成员,用于存储矩形的长和宽。数据成员可以根据访问权限(public、protected、private)被类内部或外部的代码访问和操作。

成员函数(Member Functions)

成员函数定义了类对象的行为,即类对象可以执行的操作。成员函数可以访问和操作类的数据成员,以实现特定的功能。

继续以Rectangle类为例,我们可以添加一个计算矩形面积的成员函数:

class Rectangle {
    public:
        int length;
        int width;
        int area() {
            return length * width;
        }
};

在这个例子中,area就是Rectangle类的成员函数,它通过访问length和width数据成员来计算并返回矩形的面积。

构造函数(Constructors)

构造函数是一种特殊的成员函数,用于在创建类对象时进行初始化操作。它的名字与类名相同,没有返回类型(包括void类型也不能有)。

例如,对于Rectangle类,我们可以定义一个构造函数:

class Rectangle {
    public:
        int length;
        int width;
        Rectangle(int l, int w) {
            length = l;
            width = w;
        }
};

默认构造函数(Default Constructor)

如果类中没有定义任何构造函数,编译器会自动生成一个默认构造函数。这个默认构造函数不接受任何参数,并且会对类中的数据成员进行默认初始化(对于基本数据类型,如int,初始化为0或者不确定的值;对于类类型成员,会调用其默认构造函数)。

如果类中定义了自己的构造函数(无论是带参数的还是不带参数的),编译器就不会再自动生成默认构造函数。如果还需要默认构造函数,就需要自己显式定义。例如:

class Rectangle {
    public:
        int length;
        int width;
        Rectangle() {
            length = 0;
            width = 0;
        }
        Rectangle(int l, int w) {
            length = l;
            width = w;
        }
};

初始化列表(Initialization List)

在构造函数中,可以使用初始化列表来初始化数据成员,这种方式通常比在构造函数体内部赋值更高效。例如:

class Rectangle {
    public:
        int length;
        int width;
        Rectangle(int l, int w) : length(l), width(w) {}
};

这里的length(l)和width(w)就是初始化列表,它直接在对象创建时初始化数据成员。

4. 成员函数的特性

访问控制(Access Control)

成员函数可以根据其声明所在的访问控制区域(public、protected、private)来决定是否能被类外部的代码调用。

public成员函数可以被类外部的任何代码调用;protected成员函数只能被类内部以及派生类中的代码调用;private成员函数只能被类内部的代码调用。

隐含的this指针

在成员函数内部,有一个隐含的this指针,它指向调用该成员函数的对象。例如,在Rectangle类的area函数中,实际上this->length和this->width分别指向调用area函数的那个Rectangle对象的length和width数据成员。不过在实际编写代码时,通常不需要显式地使用this指针(除非存在命名冲突等特殊情况)。

重载(Overloading)

成员函数可以像普通函数一样进行重载,即同一个类中可以有多个同名但参数列表不同(参数个数、类型或者顺序不同)的成员函数。例如:

class Rectangle {    
    public:
        int length;
        int width;
        Rectangle() {}
        Rectangle(int l, int w);
        Rectangle(int side);
};

这里定义了三个Rectangle类的构造函数,它们相互重载,可以根据不同的参数情况来创建Rectangle对象。

5. 类对象

在 C++中,类对象是根据类定义创建的具体实体。

(1). 创建类对象

可以通过以下方式创建类对象:

直接定义对象

class MyClass {
    public:
        int data;
        void display() {
            std::cout << "Data: " << data << std::endl;
        }
};
int main() {
    MyClass obj; // 创建一个 MyClass 类的对象
    obj.data = 10;
    obj.display();
    return 0;
}

使用动态内存分配(new 操作符):

class MyClass {
    public:
        int data;
        void display() {
            std::cout << "Data: " << data << std::endl;
        }
};
int main() {
    MyClass* ptr = new MyClass(); // 使用 new 创建动态对象
    ptr->data = 20;
    ptr->display();
    delete ptr; // 释放动态分配的内存
    return 0;
}

(2). 访问类对象的成员

可以通过点运算符(.)和箭头运算符(->)来访问类对象的成员

点运算符用于访问非指针类型的对象成员:

MyClass obj;
obj.data = 30;
obj.display();

箭头运算符用于访问指针类型的对象成员:

MyClass* ptr = new MyClass();
ptr->data = 40;
ptr->display();

(3). 类对象的生命周期

局部对象:在函数内部定义的对象,其生命周期从定义处开始,到函数结束时结束。

全局对象:在所有函数外部定义的对象,其生命周期从程序开始执行时开始,到程序结束时结束。

动态分配的对象:使用 new 操作符创建的对象,其生命周期由程序员通过 delete 操作符来控制。如果不及时释放动态分配的对象,会导致内存泄漏。

(4). 类对象作为函数参数和返回值

作为函数参数:可以将类对象作为函数的参数传递,有传值、传引用和传指针三种方式。

传值:会创建一个对象的副本,可能会涉及到对象的拷贝构造函数的调用,开销较大。

void processObject(MyClass obj) {
    // 对传入的对象进行处理
}

传引用:避免了对象的拷贝,提高了效率。

void processObject(MyClass& obj) {
    // 对传入的引用对象进行处理
}

传指针:也可以避免对象的拷贝,并且可以通过指针修改对象的值。

void processObject(MyClass* obj) {
    // 对传入的指针指向的对象进行处理
}

作为函数返回值:函数可以返回一个类对象。如果返回值是对象,可能会涉及到对象的拷贝构造函数和析构函数的调用。如果返回值是引用,则不会进行拷贝。

MyClass createObject() {
    MyClass obj;
    return obj;
}
MyClass& createObjectRef() {
    static MyClass obj;
    return obj;
}

(5). 类对象的初始化和赋值

初始化:可以在定义对象时使用初始化列表或构造函数来初始化对象的成员。

MyClass obj1 = {10}; // 使用初始化列表初始化对象
MyClass obj2(20); // 使用构造函数初始化对象

赋值:可以使用赋值运算符(=)将一个对象的值赋给另一个对象。如果类中没有定义赋值运算符,编译器会自动生成一个默认的赋值运算符。

MyClass obj1, obj2;
obj1.data = 30;
obj2 = obj1; // 将 obj1 的值赋给 obj2

类对象是 C++面向对象编程的核心概念之一,通过类对象可以封装数据和操作,实现代码的模块化和可维护性。

(6). C++类的定义与类对象的应用

以下是一个 C++类的完整应用例子,包括一个简单的学生类:

#include <iostream>
#include <string>
class Student {
    private:
        std::string name;
        int age;
        double grade;
    public:
        // 构造函数
        Student(std::string n, int a, double g) : name(n), age(a), grade(g) {}
        // 获取学生姓名的成员函数
        std::string getName() const {
            return name;
        }
        // 获取学生年龄的成员函数
        int getAge() const {
            return age;
        }
        // 获取学生成绩的成员函数
        double getGrade() const {
            return grade;
        }
        // 设置学生成绩的成员函数
        void setGrade(double newGrade) {
            grade = newGrade;
        }
        // 打印学生信息的成员函数
        void printInfo() const {
            std::cout << "Name: " << name << ", Age: " << age << ", Grade: " << grade << std::endl;
        }
};
int main() {
    // 创建一个学生对象
    Student s1("Alice", 18, 90.5);
    s1.printInfo();
    // 修改学生成绩并再次打印信息
    s1.setGrade(95.0);
    s1.printInfo();
    return 0;
}

在这个例子中,Student类有三个私有数据成员name、age和grade,分别表示学生的姓名、年龄和成绩。类中还定义了构造函数和一系列成员函数来操作这些数据成员,包括获取和设置学生信息的函数以及打印学生信息的函数。在main函数中,创建了一个Student对象,并通过成员函数对其进行操作和打印信息。

C++编程语言基础

C++:类的定义与声明、类对象应用