跳到主要内容

C++ 类成员

在C++面向对象编程中,类是创建对象的蓝图或模板。类成员是构成类的基本元素,它们定义了类的数据和行为。理解类成员对于掌握C++面向对象编程至关重要。

类成员的基本概念

类成员主要分为两种类型:

  1. 数据成员:存储类对象的状态信息(变量)
  2. 成员函数:定义类对象可以执行的操作(方法)

让我们通过一个简单的例子来理解类成员:

cpp
#include <iostream>
#include <string>
using namespace std;

// 定义一个学生类
class Student {
private:
// 数据成员
string name;
int age;
double grade;

public:
// 成员函数
void setInfo(string n, int a, double g) {
name = n;
age = a;
grade = g;
}

void displayInfo() {
cout << "姓名: " << name << endl;
cout << "年龄: " << age << endl;
cout << "成绩: " << grade << endl;
}
};

int main() {
Student s1;
s1.setInfo("张三", 18, 92.5);
s1.displayInfo();
return 0;
}

输出结果:

姓名: 张三
年龄: 18
成绩: 92.5

在上面的例子中,Student类包含:

  • 数据成员:nameagegrade
  • 成员函数:setInfo()displayInfo()

访问控制与访问修饰符

C++提供了三种访问修饰符来控制类成员的可访问性:

  1. public:可以被类外的任何函数访问
  2. private:只能被类内的成员函数访问
  3. protected:只能被类内的成员函数和派生类的成员函数访问
备注

如果没有指定访问修饰符,类的成员默认为private。

cpp
class Box {
public:
double getVolume() {
return length * width * height;
}

void setDimensions(double l, double w, double h) {
length = l;
width = w;
height = h;
}

private:
double length;
double width;
double height;
};

成员函数详解

在类内定义成员函数

如上面的例子所示,我们可以直接在类定义内部实现成员函数。

在类外定义成员函数

我们也可以在类外定义成员函数,这样可以使类的定义更加简洁:

cpp
class Circle {
private:
double radius;

public:
void setRadius(double r);
double getArea();
};

// 在类外定义成员函数
void Circle::setRadius(double r) {
radius = r;
}

double Circle::getArea() {
return 3.14159 * radius * radius;
}
提示

在类外定义成员函数时,需要使用作用域解析运算符(::)来指明该函数属于哪个类。

构造函数和析构函数

构造函数

构造函数是一种特殊的成员函数,在创建类的新对象时自动调用。构造函数与类同名且没有返回类型。

cpp
class Rectangle {
private:
double width;
double height;

public:
// 默认构造函数
Rectangle() {
width = 0.0;
height = 0.0;
}

// 带参数的构造函数
Rectangle(double w, double h) {
width = w;
height = h;
}

double getArea() {
return width * height;
}
};

int main() {
Rectangle rect1; // 使用默认构造函数
Rectangle rect2(5.0, 3.0); // 使用带参数的构造函数

cout << "矩形1的面积: " << rect1.getArea() << endl;
cout << "矩形2的面积: " << rect2.getArea() << endl;

return 0;
}

输出结果:

矩形1的面积: 0
矩形2的面积: 15

析构函数

析构函数是另一种特殊的成员函数,在对象被销毁时自动调用。析构函数与类同名,但前面有一个波浪号(~),且没有返回类型和参数。

cpp
class DynamicArray {
private:
int* data;
int size;

public:
// 构造函数
DynamicArray(int sz) {
size = sz;
data = new int[size]; // 动态分配内存
cout << "构造函数: 分配了内存" << endl;
}

// 析构函数
~DynamicArray() {
delete[] data; // 释放内存
cout << "析构函数: 释放了内存" << endl;
}

void setValue(int index, int value) {
if(index >= 0 && index < size)
data[index] = value;
}

int getValue(int index) {
if(index >= 0 && index < size)
return data[index];
return -1;
}
};

void testDynamicArray() {
DynamicArray arr(5);
arr.setValue(0, 10);
cout << "arr[0] = " << arr.getValue(0) << endl;
// 函数结束时,arr会被销毁,析构函数会被调用
}

int main() {
testDynamicArray();
cout << "函数已返回" << endl;
return 0;
}

输出结果:

构造函数: 分配了内存
arr[0] = 10
析构函数: 释放了内存
函数已返回

静态类成员

静态数据成员

静态数据成员是属于类而不是对象的变量。无论创建多少个对象,静态数据成员只有一个副本。

静态成员函数

静态成员函数是不依赖于任何对象的函数。它们不能访问非静态数据成员,只能调用其他静态成员函数。

cpp
class Account {
private:
static double interestRate; // 静态数据成员声明
double balance;

public:
Account(double b) : balance(b) {}

// 静态成员函数
static void setInterestRate(double rate) {
interestRate = rate;
}

static double getInterestRate() {
return interestRate;
}

double calculateInterest() {
return balance * interestRate;
}
};

// 静态数据成员定义和初始化
double Account::interestRate = 0.05;

int main() {
Account::setInterestRate(0.06); // 可以通过类名访问静态成员函数

Account acc1(1000.0);
Account acc2(2000.0);

cout << "利率: " << Account::getInterestRate() << endl;
cout << "账户1利息: " << acc1.calculateInterest() << endl;
cout << "账户2利息: " << acc2.calculateInterest() << endl;

return 0;
}

输出结果:

利率: 0.06
账户1利息: 60
账户2利息: 120
警告

静态数据成员需要在类外进行定义和初始化(除了const整型静态数据成员外)。

const成员函数

const成员函数是不会修改对象状态的函数。在函数声明中,const关键字放在函数参数列表之后。

cpp
class Temperature {
private:
double celsius;

public:
Temperature(double c) : celsius(c) {}

// const成员函数
double getCelsius() const {
return celsius;
}

double getFahrenheit() const {
return celsius * 9.0/5.0 + 32.0;
}

void setCelsius(double c) {
celsius = c;
}
};

int main() {
const Temperature temp(25.0); // 常量对象

cout << "摄氏温度: " << temp.getCelsius() << "°C" << endl;
cout << "华氏温度: " << temp.getFahrenheit() << "°F" << endl;

// temp.setCelsius(30.0); // 错误:不能通过常量对象调用非const成员函数

return 0;
}

输出结果:

摄氏温度: 25°C
华氏温度: 77°F
备注

常量对象只能调用const成员函数。

类成员的真实应用场景

让我们看一个更复杂的例子,展示类成员在实际应用中的使用:

cpp
#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Book {
private:
string title;
string author;
string isbn;
double price;
int quantity;

public:
// 构造函数
Book(string t, string a, string i, double p, int q)
: title(t), author(a), isbn(i), price(p), quantity(q) {}

// 成员函数
string getTitle() const { return title; }
string getAuthor() const { return author; }
string getISBN() const { return isbn; }
double getPrice() const { return price; }
int getQuantity() const { return quantity; }

void setPrice(double p) { price = p; }

void addStock(int q) {
if (q > 0) quantity += q;
}

bool sellCopies(int q) {
if (q <= quantity) {
quantity -= q;
return true;
}
return false;
}

double getTotalValue() const {
return price * quantity;
}

void display() const {
cout << "书名: " << title << endl;
cout << "作者: " << author << endl;
cout << "ISBN: " << isbn << endl;
cout << "单价: " << price << endl;
cout << "库存: " << quantity << endl;
cout << "库存总值: " << getTotalValue() << endl;
}
};

class Bookstore {
private:
string name;
vector<Book> inventory;
static int totalBooksSold; // 静态成员跟踪所有书店销售的总图书数

public:
Bookstore(string n) : name(n) {}

void addBook(const Book& book) {
inventory.push_back(book);
}

bool sellBook(string isbn, int quantity) {
for (size_t i = 0; i < inventory.size(); i++) {
if (inventory[i].getISBN() == isbn) {
if (inventory[i].sellCopies(quantity)) {
totalBooksSold += quantity;
return true;
}
return false;
}
}
return false;
}

void displayInventory() const {
cout << "=== " << name << " 库存 ===" << endl;
for (size_t i = 0; i < inventory.size(); i++) {
inventory[i].display();
cout << "-------------------" << endl;
}
}

static int getTotalBooksSold() {
return totalBooksSold;
}
};

int Bookstore::totalBooksSold = 0;

int main() {
// 创建一家书店
Bookstore myBookstore("学林书店");

// 添加图书到库存
Book book1("C++ Primer", "Stanley Lippman", "978-0321714114", 45.99, 10);
Book book2("Effective Modern C++", "Scott Meyers", "978-1491903995", 39.99, 5);

myBookstore.addBook(book1);
myBookstore.addBook(book2);

// 显示初始库存
myBookstore.displayInventory();

// 销售图书
cout << "\n销售3本C++ Primer..." << endl;
if (myBookstore.sellBook("978-0321714114", 3)) {
cout << "销售成功!" << endl;
} else {
cout << "销售失败,库存不足!" << endl;
}

// 显示更新后的库存
cout << "\n更新后的库存:" << endl;
myBookstore.displayInventory();

// 显示销售统计
cout << "\n总销售图书数: " << Bookstore::getTotalBooksSold() << endl;

return 0;
}

这个例子展示了一个简单的书店管理系统,其中:

  1. Book类包含书籍的属性和操作
  2. Bookstore类管理书籍库存
  3. 使用静态成员跟踪所有书店的销售总量
  4. 演示了const成员函数的使用

总结

类成员是C++面向对象编程的核心概念。在本文中,我们学习了:

  1. 数据成员和成员函数的基本概念
  2. 访问控制和访问修饰符(public、private、protected)
  3. 在类内和类外定义成员函数
  4. 构造函数和析构函数
  5. 静态成员(数据和函数)
  6. const成员函数
  7. 类成员在实际应用中的使用

正确理解和使用类成员是编写高质量、可维护C++代码的基础。随着你对C++编程的深入学习,你会发现更多使用类成员的高级技巧。

练习

  1. 创建一个Point类,表示2D平面上的点:

    • 添加私有数据成员xy
    • 提供构造函数、getter和setter方法
    • 添加计算到另一个点距离的方法
  2. 扩展Circle类:

    • 添加中心点(使用Point类)和半径
    • 提供计算周长和面积的方法
    • 添加一个方法判断一个点是否在圆内
  3. 创建一个Counter类:

    • 使用静态成员记录创建了多少个Counter对象
    • 为每个对象提供一个唯一ID
    • 添加一个静态方法返回创建的对象总数

通过这些练习,你将能够更好地理解和应用C++中的类成员概念。