C++类与对象核心知识点
·
一、核心概念:类与对象的本质
- 类:C++的核心抽象机制,是数据(成员变量)和操作(成员函数)的封装体,相当于“对象的模板”,定义对象的共同属性和行为。
- 对象:类的实例化结果(占用实际内存),一个类可创建多个对象,各对象共享类的成员函数,但拥有独立的成员变量。
- 类比:类=“汽车设计图纸”,对象=“具体的一辆汽车”(图纸不占空间,汽车占空间)。
二、类的定义与访问控制
- 类的定义语法(struct与class的区别)
// 1. class关键字(默认访问权限private)
class Car {
private: // 私有成员(仅类内可访问)
string brand; // 成员变量(属性)
int speed;
public: // 公有成员(类内+类外可访问)
// 成员函数(行为)
void setInfo(string b, int s) { // 赋值函数
brand = b;
speed = s;
}
void showInfo() { // 展示函数
cout << "品牌:" << brand << ",速度:" << speed << "km/h" << endl;
}
protected: // 保护成员(类内+子类可访问)
int weight;
};
// 2. struct关键字(默认访问权限public,兼容C语言结构体)
struct Student {
string name; // 默认public
int age;
void show() {
cout << "姓名:" << name << ",年龄:" << age << endl;
}
};
- 访问权限控制(3种关键字)
| 权限关键字 | 访问范围 | 核心用途 |
|---|---|---|
| private | 仅类内可访问 | 封装核心数据,避免外部直接修改(如汽车的发动机参数) |
| public | 类内+类外可访问 | 提供对外接口(如setter/getter函数、功能函数) |
| protected | 类内+子类可访问 | 用于继承,让子类复用父类成员(如动物类的“呼吸”方法) |
三、对象的创建与初始化
- 对象的3种创建方式
// 方式1:栈上创建(自动释放内存,常用)
Car c1;
c1.setInfo("奔驰", 120);
c1.showInfo();
// 方式2:堆上创建(new关键字,手动释放delete)
Car* c2 = new Car();
c2->setInfo("宝马", 150); // 指针用->访问成员
c2->showInfo();
delete c2; // 必须手动释放,避免内存泄漏
// 方式3:直接初始化(调用构造函数)
Car c3("奥迪", 180); // 需配合带参构造函数使用
- 构造函数(对象初始化的核心)
- 作用:对象创建时自动调用,初始化成员变量(默认无参构造函数)。
- 语法规则:
- 函数名与类名完全一致,无返回值(连void都不写);
- 可重载(多个构造函数,参数列表不同);
- 若用户未定义,编译器自动生成“默认无参构造函数”(空实现)。
class Car {
private:
string brand;
int speed;
public:
// 1. 无参构造函数(默认构造)
Car() {
brand = "未知品牌";
speed = 0;
}
// 2. 带参构造函数(重载)
Car(string b, int s) {
brand = b;
speed = s;
}
// 3. 拷贝构造函数(用已有对象初始化新对象)
Car(const Car& other) { // const避免修改原对象,&避免值拷贝
brand = other.brand;
speed = other.speed;
}
};
// 调用示例
Car c1; // 无参构造
Car c2("特斯拉", 200); // 带参构造
Car c3 = c2; // 拷贝构造(等价于Car c3(c2))
- 析构函数(对象销毁时清理资源)
- 作用:对象释放时自动调用,释放堆内存、关闭文件等(如new的对象)。
- 语法规则:
- 函数名前加 ~ ,与类名一致,无返回值、无参数;
- 不可重载(仅1个析构函数);
- 若用户未定义,编译器自动生成默认析构函数(空实现)。
class Car {
private:
string* brand; // 堆上的字符串(需手动释放)
public:
// 构造函数(new分配内存)
Car(string b) {
brand = new string(b); // 堆内存分配
}
// 析构函数(delete释放内存)
~Car() {
delete brand; // 必须手动释放,避免内存泄漏
cout << "析构函数调用,内存已释放" << endl;
}
};
四、类的核心特性:封装、继承、多态
- 封装(数据隐藏与接口暴露)
- 核心思想:将成员变量设为 private ,通过 public 的成员函数(setter/getter)访问和修改,避免外部直接操作数据。
- 实操示例:
class Person {
private:
int age; // 私有成员,外部不可直接修改
public:
// setter函数(设置值,可加逻辑校验)
void setAge(int a) {
if (a >= 0 && a <= 120) { // 校验年龄合法性
age = a;
} else {
cout << "年龄输入错误!" << endl;
}
}
// getter函数(获取值)
int getAge() {
return age;
}
};
// 外部访问
Person p;
p.setAge(20); // 正确:通过setter设置
cout << p.getAge() << endl; // 正确:通过getter获取
// p.age = 30; // 错误:private成员不可直接访问
- 继承(代码复用)
- 核心思想:子类(派生类)继承父类(基类)的成员变量和成员函数,同时可添加新成员或重写父类函数。
- 语法与关键规则:
// 父类(基类)
class Animal {
protected:
string name;
public:
void eat() {
cout << name << "在吃东西" << endl;
}
};
// 子类(派生类):public继承(常用)
class Dog : public Animal {
private:
string color;
public:
// 子类构造函数(需初始化父类成员)
Dog(string n, string c) {
name = n; // 继承protected成员,可直接访问
color = c;
}
// 重写父类函数(多态基础)
void eat() {
cout << color << "的" << name << "在吃骨头" << endl;
}
// 新增子类独有的函数
void bark() {
cout << name << "在汪汪叫" << endl;
}
};
// 调用示例
Dog d("旺财", "黄色");
d.eat(); // 调用子类重写的eat()
d.bark(); // 调用子类新增的bark()
- 继承权限(3种方式):
继承方式 父类public成员 父类protected成员 父类private成员
public 子类public 子类protected 不可访问
protected 子类protected 子类protected 不可访问
private 子类private 子类private 不可访问
- 多态(一个接口,多种实现)
- 核心思想:父类指针/引用指向子类对象时,调用同名函数会执行子类的重写版本(需配合 virtual 关键字)。
- 关键条件:
- 父类函数声明为 virtual (虚函数);
- 子类重写该虚函数(函数名、参数列表、返回值完全一致);
- 通过父类指针/引用调用函数。
class Animal {
public:
// 虚函数(加virtual)
virtual void makeSound() {
cout << "动物在发出声音" << endl;
}
};
class Cat : public Animal {
public:
// 重写虚函数
void makeSound() override { // override关键字(C++11+),显式声明重写
cout << "猫咪在喵喵叫" << endl;
}
};
class Dog : public Animal {
public:
void makeSound() override {
cout << "小狗在汪汪叫" << endl;
}
};
// 多态调用(核心)
void animalSound(Animal& a) { // 父类引用
a.makeSound(); // 调用子类重写的函数
}
// 测试
Cat c;
Dog d;
animalSound(c); // 输出:猫咪在喵喵叫
animalSound(d); // 输出:小狗在汪汪叫
五、其他关键知识点
- 静态成员(static)
- 特性:属于类本身,所有对象共享,生命周期与程序一致(不依赖对象)。
- 实操示例:
class Counter {
public:
static int count; // 静态成员变量(类内声明,类外初始化)
static void addCount() { // 静态成员函数(无this指针,只能访问静态成员)
count++;
}
};
// 静态成员变量类外初始化(必须写,否则编译错误)
int Counter::count = 0;
// 调用示例(无需创建对象,直接通过类名访问)
Counter::addCount();
cout << Counter::count << endl; // 输出:1
- 友元(friend)
- 核心作用:让外部函数/类访问当前类的 private / protected 成员(打破封装,谨慎使用)。
- 3种形式:
class Car {
private:
int speed;
// 1. 友元函数(外部函数可访问类内成员)
friend void showSpeed(Car& c);
// 2. 友元类(整个类的函数都可访问)
friend class Mechanic;
public:
Car(int s) : speed(s) {}
};
// 友元函数实现
void showSpeed(Car& c) {
cout << "车速:" << c.speed << endl; // 可访问private成员
}
// 友元类
class Mechanic {
public:
void modifySpeed(Car& c, int s) {
c.speed = s; // 可访问private成员
}
};
- 常成员(const)
- 常成员变量:初始化后不可修改,必须通过构造函数初始化列表赋值。
- 常成员函数:不可修改类的成员变量( mutable 变量除外),声明时在函数末尾加 const 。
class Person {
private:
const string id; // 常成员变量(不可修改)
string name;
mutable int count; // 可在常函数中修改
public:
// 初始化列表(必须用于常成员变量初始化)
Person(string i, string n) : id(i), name(n), count(0) {}
// 常成员函数(末尾加const)
void showInfo() const {
cout << "ID:" << id << ",姓名:" << name << endl;
count++; // mutable变量可修改
// name = "张三"; // 错误:常函数不可修改普通成员变量
}
};
六、核心易错点
- 构造函数无返回值,不可写 void ;
- 堆上创建的对象( new )必须手动 delete ,否则内存泄漏;
- 拷贝构造函数的参数必须是“常量引用”( const 类名& ),避免无限递归;
- 多态的实现必须满足“虚函数+重写+父类指针/引用”,缺一不可;
- 静态成员变量必须在类外初始化,否则编译报错。
更多推荐


所有评论(0)