第八章:C++中的类与对象介绍
在面向对象编程(Object-Oriented Programming,简称OOP)中,类和对象是核心概念。C++是一种支持面向对象编程的语言,下面我们将详细介绍C++中类与对象的概念,并通过丰富的代码示例和实际案例来帮助您更好地理解。
类与对象的基本概念
类(Class)
在C++中,类是一种用户自定义的数据类型,它通过封装数据和对数据的操作来描述具有相似特征和行为的一组对象。类可以看作是一个模板或蓝图,它定义了对象的属性(成员变量)和行为(成员函数)。
以下是一个简单的类的示例:
#include <iostream> using namespace std; // 定义一个点类 class Point { public: // 成员变量 int x; int y; // 成员函数 void display() { cout << "x = " << x << ", y = " << y << endl; } }; int main() { // 创建一个Point对象 Point p1; p1.x = 10; p1.y = 20; p1.display(); return 0; }
运行结果:
x = 10, y = 20
上述代码中,我们定义了一个Point类,它具有两个成员变量x和y,以及一个成员函数display()。在main()函数中,我们创建了一个Point类的对象p1,并通过对象访问和修改了其成员变量,并调用了成员函数。
对象(Object)
对象是类的实例化,也就是根据类的定义创建的具体实体。每个对象都有自己的一组属性值,代表该类的特定实例。
以上面的点类为例,我们可以创建多个点对象,每个对象表示一个不同的坐标点。
#include <iostream> using namespace std; class Point { public: int x; int y; void display() { cout << "x = " << x << ", y = " << y << endl; } }; int main() { Point p1; p1.x = 10; p1.y = 20; p1.display(); Point p2; p2.x = 30; p2.y = 40; p2.display(); return 0; }
运行结果:
x = 10, y = 20 x = 30, y = 40
上述代码中,我们创建了两个Point类的对象p1和p2,它们分别代表了不同的坐标点。每个对象都有自己独立的x和y属性值。
构造函数与析构函数
构造函数(Constructor)
构造函数是一种特殊的成员函数,用于在对象创建时进行初始化操作。它的名称与类的名称相同,没有返回类型,且只能在对象创建时自动调用。
以下是一个示例,演示如何定义和使用构造函数:
#include <iostream> using namespace std; class Point { public: int x; int y; // 默认构造函数 Point() { cout << "调用默认构造函数" << endl; x = 0; y = 0; } // 带参数的构造函数 Point(int a, int b) { cout << "调用带参数的构造函数" << endl; x = a; y = b; } void display() { cout << "x = " << x << ", y = " << y << endl; } }; int main() { Point p1; p1.display(); Point p2(10, 20); p2.display(); return 0; }
运行结果:
调用默认构造函数 x = 0, y = 0 调用带参数的构造函数 x = 10, y = 20
在上述代码中,我们为Point类定义了两个构造函数:一个是默认构造函数,另一个是带参数的构造函数。默认构造函数会在对象创建时自动调用,用于将x和y初始化为0。带参数的构造函数则接收x和y的初始值,在对象创建时进行初始化。
析构函数(Destructor)
析构函数是用于在对象销毁时进行清理操作的特殊成员函数。它的名称与类的名称相同,前面加上波浪号(~),没有参数和返回类型,在对象被删除时自动调用。
以下是一个示例,展示如何定义和使用析构函数:
#include <iostream> using namespace std; class Point { public: int x; int y; Point() { cout << "调用构造函数" << endl; x = 0; y = 0; } ~Point() { cout << "调用析构函数" << endl; } void display() { cout << "x = " << x << ", y = " << y << endl; } }; int main() { Point p1; p1.display(); { // 代码块内创建的对象会在其作用域结束后自动销毁 Point p2(10, 20); p2.display(); } return 0; }
运行结果:
调用构造函数 x = 0, y = 0 调用构造函数 x = 10, y = 20 调用析构函数
在上述代码中,我们为Point类定义了一个析构函数。这个析构函数会在对象被销毁、离开作用域时自动调用。在示例中,对象p2在作用域结束后被销毁,因此析构函数被调用。
成员访问控制
C++中,类的成员(包括变量和函数)可以通过访问控制符指定其可访问性。C++提供了三种访问控制符:public、private和protected。
- public:公有成员可以在类的内部和外部被访问。
- private:私有成员只能在类的内部被访问,外部无法直接访问。
- protected:受保护成员与私有成员类似,但可以被派生类访问。
以下是一个示例,展示不同访问控制符的使用:
#include <iostream> using namespace std; class Rectangle { public: // 公有成员函数 void setDimensions(int length, int width) { if (length > 0 && width > 0) { this->length = length; this->width = width; } } int getArea() { return length * width; } private: // 私有成员变量 int length; int width; }; int main() { Rectangle rect; // 访问公有成员函数 rect.setDimensions(5, 10); // 访问公有成员函数 cout << "面积:" << rect.getArea() << endl; // 下面这行代码会导致编译错误,因为length和width是私有成员,无法在外部访问 // rect.length = 2; return 0; }
运行结果:
面积:50
在上述代码中,setDimensions()和getArea()是公有成员函数,可通过对象调用。而length和width是私有成员变量,不能直接在类外部进行访问。
静态成员
在C++中,静态成员是类的成员,它属于整个类而不是类的任何对象。它与类相关联,而不是与对象关联。静态成员在所有类的对象之间共享,并且可以直接访问,无需创建对象。
下面是一个示例,介绍如何定义和使用静态成员:
#include <iostream> using namespace std; class Circle { public: double radius; // 普通成员变量 static int count; // 静态成员变量 Circle(double r) { radius = r; count++; } void display() { cout << "半径:" << radius << endl; cout << "总数:" << count << endl; } static void showCount() { cout << "当前圆的数量:" << count << endl; } }; int Circle::count = 0; // 静态成员变量需要在类外进行初始化 int main() { Circle c1(1.5); Circle c2(2.5); c1.display(); // 访问普通成员变量和函数 c2.display(); Circle::showCount(); // 直接通过类名访问静态成员函数 return 0; }
运行结果:
半径:1.5 总数:2 半径:2.5 总数:2 当前圆的数量:2
在上述代码中,我们定义了一个Circle类,其中包含一个普通成员变量radius和一个静态成员变量count。在构造函数中,每次创建对象都会递增count的值。同时,我们还定义了一个普通成员函数display()来显示圆的半径和当前count的值,以及一个静态成员函数showCount()来直接显示当前圆的数量。
通过运行结果可以看出,虽然我们只创建了两个Circle对象,但count的值被共享,并且通过静态成员函数showCount()可以直接访问到它。
类的友元
在C++中,可以使用友元(friend)关键字来声明一个函数或类是另一个类的友元。友元函数或类可以访问声明它为友元的类的私有成员。
以下是一个示例,展示如何使用类的友元:
#include <iostream> using namespace std; class Rectangle { private: int length; int width; public: Rectangle(int l, int w) { length = l; width = w; } // 声明友元函数 friend int getArea(Rectangle r); }; // 定义友元函数,可以访问Rectangle类的私有成员 int getArea(Rectangle r) { return r.length * r.width; } int main() { Rectangle rect(5, 10); cout << "面积:" << getArea(rect) << endl; return 0; }
运行结果:
面积:50 • 1
在上述代码中,我们定义了一个Rectangle类,它有两个私有成员变量length和width。然后我们声明了一个友元函数getArea(),它可以直接访问Rectangle类的私有成员。在main()函数中,我们创建了一个Rectangle对象rect,并通过友元函数计算其面积。
继承
继承是面向对象编程中的一个重要概念,它允许我们创建一个新的类(派生类/子类),从已存在的类(基类/父类)继承属性和行为。派生类可以从基类继承公有成员、保护成员和私有成员。
以下是一个示例,展示如何使用继承:
#include <iostream> using namespace std; // 基类 class Shape { protected: int width; int height; public: void setDimensions(int w, int h) { width = w; height = h; } }; // 派生类 class Rectangle : public Shape { public: int getArea() { return width * height; } }; int main() { Rectangle rect; rect.setDimensions(5, 10); cout << "矩形的面积:" << rect.getArea() << endl; return 0; }
运行结果:
矩形的面积:50
在上述代码中,我们有一个基类Shape和一个派生类Rectangle。Rectangle类继承了Shape类的width和height成员变量,以及setDimensions()函数。在main()函数中,我们创建了一个Rectangle对象,并通过调用基类的成员函数setDimensions()设置其尺寸。然后,我们通过派生类的成员函数getArea()计算矩形的面积。