前言
C++ 是一种面向对象的编程语言,类和对象是其核心特性之一。类是一种用户自定义的数据类型,用于封装数据和对数据的操作。对象是类的实例,具有类定义的属性和行为。
一、基本概念
1. 类(Class)
定义:类是用户自定义的数据类型,是创建对象的蓝图或模板
组成:
数据成员(属性/特征)
成员函数(方法/行为)
访问修饰符(控制访问权限)
2. 对象(Object)
定义:对象是类的实例,占用实际内存空间
特点:每个对象都有自己的数据成员副本,但共享成员函数
二、类的定义与使用
1. 基本语法
class ClassName {
// 访问修饰符
private:
// 私有成员(只能在类内部访问)
protected:
// 受保护成员(类内部和派生类可访问)
public:
// 公共成员(任何地方都可访问)
// 构造函数
ClassName();
// 成员函数
returnType functionName(parameters);
// 析构函数
~ClassName();
};
2. 访问修饰符
修饰符 | 访问权限 |
---|---|
private | 仅类内部可访问(默认) |
protected | 类内部和派生类可访问 |
public | 任何地方都可访问 |
三、对象的创建与使用
1. 创建对象
// 方式1:栈上分配
ClassName obj1; // 调用默认构造函数
ClassName obj2(params); // 调用带参构造函数
// 方式2:堆上分配
ClassName* ptr = new ClassName(); // 动态分配
delete ptr; // 必须手动释放
2. 访问成员
obj.memberVariable; // 访问数据成员
obj.memberFunction(); // 调用成员函数
ptr->memberVariable; // 指针访问数据成员
ptr->memberFunction(); // 指针调用成员函数
四、构造函数与析构函数
1. 构造函数
class Person {
private:
string name;
int age;
public:
// 默认构造函数
Person() : name("Unknown"), age(0) {}
// 参数化构造函数
Person(string n, int a) : name(n), age(a) {}
};
2. 析构函数
class ResourceHolder {
private:
int* data;
public:
ResourceHolder(int size) {
data = new int[size];
}
~ResourceHolder() {
delete[] data; // 释放资源
cout << "资源已释放" << endl;
}
};
五、this指针
作用:指向当前对象的指针
用途:
区分成员变量和局部变量
返回对象自身引用
在成员函数中访问当前对象
class Example {
private:
int value;
public:
void setValue(int value) {
this->value = value; // 使用this区分同名变量
}
Example& getThis() {
return *this; // 返回当前对象的引用
}
};
六、静态成员
1. 静态数据成员
class Counter {
private:
static int count; // 声明
public:
Counter() { count++; }
~Counter() { count--; }
static int getCount() { return count; }
};
int Counter::count = 0; // 定义并初始化
要注意的是这里初始化要在类外初始化
2. 静态成员函数
class MathUtils {
public:
static double square(double x) {
return x * x;
}
};
// 调用方式
double result = MathUtils::square(5.0);
如果要在类外写的话要加上作用域在调用时应注意变量类型
七、常成员与常对象
1. 常成员函数
class BankAccount {
private:
double balance;
public:
double getBalance() const { // 不会修改对象状态
return balance;
}
};
2. 常对象
const BankAccount acc; // 常对象
double b = acc.getBalance(); // 只能调用常成员函数
这里注意常对象只能调用常成员函数
类的应用
#include <iostream>
#include <string>
using namespace std;
class Student {
private:
string name;
int id;
double gpa;
public:
// 构造函数
Student(string n, int i, double g) : name(n), id(i), gpa(g) {}
// 成员函数
void display() const {
cout << "学生姓名: " << name << endl;
cout << "学号: " << id << endl;
cout << "GPA: " << gpa << endl;
}
void study(int hours) {
gpa += hours * 0.1;
if (gpa > 4.0) gpa = 4.0;
}
// Getter/Setter
string getName() const { return name; }
void setName(string n) { name = n; }
double getGPA() const { return gpa; }
};
int main() {
// 创建对象
Student stu1("张三", 1001, 3.5);
Student stu2("李四", 1002, 3.2);
// 使用对象
stu1.display();
stu2.study(5);
cout << stu2.getName() << "的新GPA: " << stu2.getGPA() << endl;
return 0;
}
类定义部分:定义了一个名为
Student
的类,包含三个私有数据成员(name
、id
、gpa
)和多个公有成员函数。这种将数据私有、方法公有的设计体现了面向对象编程的封装特性。构造函数:采用初始化列表语法
:name(n), id(i), gpa(g)
来初始化成员变量,这种方式比在构造函数体内赋值更高效,特别是对于类类型成员。成员函数:包含了显示信息的
display()
方法、模拟学习的study()
方法以及获取/设置属性的方法。const
修饰的方法承诺不会修改对象状态。
使用注意事项
初始化列表:在构造函数中,应优先使用初始化列表而非构造函数体内赋值,特别是对于const成员、引用成员和类类型成员。
const方法:不修改对象状态的成员函数都应声明为const,这样const对象也能调用这些方法,提高代码的灵活性。
封装程度:应根据实际需求合理设计getter/setter,不是所有私有成员都需要提供公开访问接口,特别是像GPA这样需要受控修改的数据。
参数传递:对于字符串等可能较大的参数,应考虑使用const引用传递(如
setName(const string& n)
),避免不必要的拷贝。
总结
使用类时需要掌握几个关键点:构造函数用于初始化对象,析构函数用于清理资源;this指针指向当前对象,用于解决命名冲突;静态成员属于类而非对象,被所有对象共享;const成员函数保证不修改对象状态。类设计应遵循封装原则,将数据设为private,通过public方法提供访问接口,必要时使用protected为派生类保留访问权限。