C++文章目录中每个主题的详解,内容简洁、清晰,涵盖核心概念,并尽量避免冗长叙述
·
C++文章目录中每个主题的详解,内容简洁、清晰,涵盖核心概念,并尽量避免冗长叙述。如果需要更详细的代码示例或进一步解释某个部分,请告诉我!
一. 类和对象
1.1 封装
1.1.1 封装的意义
封装是面向对象编程的核心特性之一,通过将数据(成员变量)和操作数据的方法(成员函数)捆绑在一起,并控制访问权限,隐藏对象的内部实现细节。
- 意义:
- 数据保护:防止外部直接访问和修改对象内部数据,保证数据安全。
- 接口简化:提供公共接口(如get/set方法),隐藏复杂实现,提高代码可维护性。
- 模块化:将功能封装成独立单元,便于代码复用和修改。
1.1.2 struct和class区别
在C++中,struct和class都可以定义类,主要区别如下:
- 默认访问权限:
struct:成员默认是public。class:成员默认是private。
- 使用场景:
struct:常用于数据结构,强调数据聚合,较少包含复杂逻辑。class:常用于面向对象设计,包含数据和行为,强调封装。
- 其他:除默认访问权限外,二者在功能上几乎无差别,
struct支持继承、多态等。
1.1.3 成员属性设置为私有
将成员属性设为private是封装的重要实践:
- 原因:
- 防止外部直接修改成员变量,保护数据完整性。
- 通过
public的get/set方法控制访问,增加灵活性(如验证输入)。
- 实现:
class Person { private: string name; public: void setName(string n) { if (n != "") name = n; } string getName() { return name; } };
1.2 对象的初始化和清理
1.2.1 构造函数和析构函数
- 构造函数:
- 与类同名,无返回值,对象创建时自动调用,用于初始化成员变量。
- 可重载,支持多种初始化方式。
- 析构函数:
- 名称为
~类名,无参数无返回值,对象销毁时自动调用,用于释放资源(如动态内存)。
class Person { public: Person() { cout << "Constructor" << endl; } ~Person() { cout << "Destructor" << endl; } }; - 名称为
1.2.2 构造函数的分类及调用
- 分类:
- 无参构造函数:
Person() {},默认初始化。 - 有参构造函数:
Person(string n) { name = n; },带参数初始化。 - 拷贝构造函数:
Person(const Person& p) { name = p.name; },通过已有对象初始化新对象。
- 无参构造函数:
- 调用方式:
- 括号法:
Person p("Alice"); - 显示法:
Person p = Person("Alice"); - 隐式转换法:
Person p = "Alice";(需有单参数构造函数) - 拷贝构造:
Person p2 = p1;
- 括号法:
1.2.3 拷贝构造函数调用时机
拷贝构造函数在以下场景自动调用:
- 用已有对象初始化新对象:
Person p2 = p1; - 对象作为函数参数按值传递:
void func(Person p) {} - 对象作为函数返回值按值返回:
Person func() { return Person(); }
1.2.4 构造函数调用规则
- 系统默认提供:无参构造函数、拷贝构造函数、析构函数。
- 如果定义了有参构造函数,系统不再提供默认无参构造函数,但仍提供默认拷贝构造函数。
- 如果定义了拷贝构造函数,系统不再提供其他构造函数。
1.2.5 深拷贝与浅拷贝
- 浅拷贝:默认拷贝构造函数只拷贝值(包括指针地址),可能导致多个对象共享同一块动态内存,析构时重复释放引发错误。
- 深拷贝:为指针成员重新分配内存并复制数据,避免浅拷贝问题。
class Person { private: int* age; public: Person(int a) { age = new int(a); } Person(const Person& p) { age = new int(*p.age); } // 深拷贝 ~Person() { delete age; } };
1.2.6 初始化列表
用于在构造函数中初始化成员变量,效率高于在构造函数体内赋值。
- 语法:
class Person { private: string name; int age; public: Person(string n, int a) : name(n), age(a) {} }; - 用途:
- 初始化
const成员或引用成员。 - 初始化无默认构造函数的类成员。
- 提高初始化效率。
- 初始化
1.2.7 类对象作为类成员
类对象可以作为另一个类的成员,构造和析构顺序如下:
- 构造顺序:先构造成员对象,再构造本类。
- 析构顺序:先析构本类,再析构成员对象(与构造顺序相反)。
class Phone { public: Phone() { cout << "Phone Constructor" << endl; } ~Phone() { cout << "Phone Destructor" << endl; } }; class Person { Phone phone; public: Person() { cout << "Person Constructor" << endl; } ~Person() { cout << "Person Destructor" << endl; } };
1.2.8 静态成员
- 静态成员变量:用
static修饰,属于类而非对象,所有对象共享同一份数据,在程序开始时分配内存。class Person { public: static int count; // 声明 }; int Person::count = 0; // 定义并初始化 - 静态成员函数:用
static修饰,只能访问静态成员,不能访问非静态成员,无this指针。static void func() { cout << count << endl; }
1.3 C++对象模型和this指针
1.3.1 成员变量和成员函数分开存储
- 对象模型:
- 成员变量存储在对象中,每个对象有自己的副本。
- 成员函数存储在代码段,所有对象共享。
- 内存布局:对象只存储成员变量,函数地址由编译器管理。
1.3.2 this指针概念
this是指向当前对象的指针,隐式存在于非静态成员函数中,用于区分对象实例。- 用途:
- 解决成员变量与参数名冲突:
this->name = name; - 返回对象自身:
return *this;
- 解决成员变量与参数名冲突:
1.3.3 空指针访问成员函数
- 空指针(如
Person* p = nullptr)调用非静态成员函数可能导致崩溃,除非函数不访问成员变量。class Person { public: void func() { cout << "No member access" << endl; } // 安全 void func2() { cout << name << endl; } // 崩溃 private: string name; }; Person* p = nullptr; p->func(); // 正常 p->func2(); // 崩溃
1.3.4 const修饰成员函数
const成员函数(void func() const)承诺不修改成员变量。- 只能调用其他
const成员函数,适用于只读操作。class Person { private: string name; public: void show() const { cout << name << endl; } };
1.4 友元
友元允许外部函数或类访问类的私有成员,打破封装但提供灵活性。
1.4.1 全局函数做友元
- 声明全局函数为友元,允许其访问类的私有成员。
class Person { friend void print(Person& p); private: string name; }; void print(Person& p) { cout << p.name << endl; }
1.4.2 类做友元
- 声明一个类为友元,允许其所有成员函数访问私有成员。
class Friend; class Person { friend class Friend; private: string name; }; class Friend { public: void visit(Person& p) { cout << p.name << endl; } };
1.4.3 成员函数做友元
- 声明某个类的成员函数为友元,仅该函数可访问私有成员。
class Friend; class Person { friend void Friend::visit(Person&); private: string name; }; class Friend { public: void visit(Person& p) { cout << p.name << endl; } };
1.5 运算符重载
运算符重载允许自定义运算符的行为,使类对象支持类似内置类型的操作。
1.5.1 加号运算符重载
- 重载
+运算符,返回新对象。class Person { public: int age; Person operator+(const Person& p) { Person temp; temp.age = this->age + p.age; return temp; } };
1.5.2 左移运算符重载
- 重载
<<以支持cout输出,通常声明为全局友元函数。class Person { friend ostream& operator<<(ostream& out, const Person& p); private: string name; }; ostream& operator<<(ostream& out, const Person& p) { out << p.name; return out; }
1.5.3 递增运算符重载
- 前置++:
++obj,返回修改后的对象。 - 后置++:
obj++,返回修改前的对象。class Person { public: int age; Person& operator++() { age++; return *this; } // 前置 Person operator++(int) { Person temp = *this; age++; return temp; } // 后置 };
1.5.4 赋值运算符重载
- 重载
=以支持深拷贝。class Person { private: int* age; public: Person& operator=(const Person& p) { if (age) delete age; age = new int(*p.age); return *this; } };
1.5.5 关系运算符重载
- 重载
==、!=等,返回布尔值。class Person { public: int age; bool operator==(const Person& p) { return age == p.age; } };
1.5.6 函数调用运算符重载
- 重载
(),使对象像函数一样调用,称为“仿函数”。class MyFunc { public: int operator()(int a, int b) { return a + b; } }; MyFunc f; cout << f(1, 2); // 输出3
1.6 继承
1.6.1 继承的基本语法
继承允许子类复用父类的成员,减少代码冗余。
- 语法:
class Base { public: int x; }; class Derived : public Base { public: int y; };
1.6.2 继承方式
- public继承:父类
public成员保持public,protected保持protected。 - protected继承:父类
public和protected成员变为子类的protected。 - private继承:父类
public和protected成员变为子类的private。
1.6.3 继承中的对象模型
- 子类对象包含父类成员和自身成员,内存布局按声明顺序排列。
- 父类的私有成员被继承但不可直接访问。
1.6.4 继承中构造和析构顺序
- 构造:先调用父类构造函数,再调用子类构造函数。
- 析构:先调用子类析构函数,再调用父类析构函数。
class Base { ... }; class Derived : public Base { ... };
1.6.5 继承同名成员处理方式
- 子类访问父类同名成员需加作用域:
Base::member。 - 如果子类重定义同名成员,父类成员被隐藏。
1.6.6 继承同名静态成员处理方式
- 静态成员通过类名或对象访问:
Base::staticVar或obj.staticVar。 - 子类同名静态成员隐藏父类成员,需用
Base::访问。
1.6.7 多继承语法
- 一个子类继承多个父类:
class Derived : public Base1, public Base2 {}; - 注意:多继承可能导致复杂性和歧义(如菱形继承)。
1.6.8 菱形继承
- 问题:多个父类继承自同一基类,导致子类包含多份基类成员。
- 解决:使用虚继承(
virtual public Base),使子类共享一份基类成员。class Base { public: int x; }; class B1 : virtual public Base {}; class B2 : virtual public Base {}; class Derived : public B1, public B2 {};
1.7 多态
1.7.1 多态的基本概念
多态允许不同类的对象对同一消息作出不同响应,分为静态多态(函数重载、模板)和动态多态(虚函数)。
- 动态多态条件:
- 继承关系。
- 父类函数声明为
virtual。 - 子类重写父类虚函数。
- 父类指针或引用调用虚函数。
1.7.2 多态案例一-计算器类
通过虚函数实现不同运算方式:
class Calculator {
public:
virtual int calculate(int a, int b) { return 0; }
};
class Add : public Calculator {
public:
int calculate(int a, int b) override { return a + b; }
};
1.7.3 纯虚函数和抽象类
- 纯虚函数:
virtual void func() = 0;无实现,子类必须重写。 - 抽象类:包含纯虚函数的类,不能实例化,仅作为基类。
class Shape { public: virtual void draw() = 0; };
1.7.4 多态案例二-制作饮品
通过多态实现不同饮品制作流程:
class Drink {
public:
virtual void make() = 0;
};
class Coffee : public Drink {
public:
void make() override { cout << "Make Coffee" << endl; }
};
1.7.5 虚析构和纯虚析构
- 虚析构:
virtual ~Base();,确保通过父类指针删除子类对象时调用子类析构函数。 - 纯虚析构:
virtual ~Base() = 0;,需提供实现,防止内存泄漏。class Base { public: virtual ~Base() = 0; }; Base::~Base() {}
1.7.6 多态案例三-电脑组装
通过多态实现不同品牌电脑的组装:
class Component {
public:
virtual void install() = 0;
};
class CPU : public Component {
public:
void install() override { cout << "Install CPU" << endl; }
};
以上是对目录中每个主题的简明讲解,涵盖了C++面向对象编程的核心概念。如果需要针对某个主题提供更详细的代码示例、进一步解释,或有其他问题,请告诉我!
更多推荐


所有评论(0)