C++从入门到类和对象完全指南

引言

C++作为一门强大的编程语言,自1983年诞生以来,一直占据着系统级编程和性能敏感领域的核心地位。它不仅继承了C语言的高效性,更引入了面向对象编程等现代特性,成为了工业级软件开发的首选语言之一。本指南将从C++基础开始,逐步深入探讨类和对象的核心概念,帮助你构建完整的C++知识体系。

目录

引言

第一部分:C++入门基础

[1.1 C++简介与发展历史](#1.1 C++简介与发展历史)

[1.2 C++版本演进](#1.2 C++版本演进)

[1.3 C++的重要性与应用领域](#1.3 C++的重要性与应用领域)

[1.4 C++学习建议与书籍推荐](#1.4 C++学习建议与书籍推荐)

[1.5 第一个C++程序](#1.5 第一个C++程序)

[1.6 命名空间(Namespace)](#1.6 命名空间(Namespace))

[1.7 输入输出](#1.7 输入输出)

[1.8 缺省参数(默认参数)](#1.8 缺省参数(默认参数))

[1.9 函数重载(Overload)](#1.9 函数重载(Overload))

[1.10 引用(Reference)](#1.10 引用(Reference))

[1.11 内联函数(Inline)](#1.11 内联函数(Inline))

[1.12 nullptr](#1.12 nullptr)

第二部分:类和对象(上)

[2.1 类的定义](#2.1 类的定义)

[2.2 访问限定符](#2.2 访问限定符)

[2.3 类域](#2.3 类域)

[2.4 实例化](#2.4 实例化)

[2.5 对象大小](#2.5 对象大小)

[2.6 this指针](#2.6 this指针)

[2.7 C++与C实现Stack的对比](#2.7 C++与C实现Stack的对比)

第三部分:类和对象(中)

[3.1 类的默认成员函数概述](#3.1 类的默认成员函数概述)

[3.2 构造函数](#3.2 构造函数)

[3.3 析构函数](#3.3 析构函数)

[3.4 拷贝构造函数](#3.4 拷贝构造函数)

[3.5 赋值运算符重载](#3.5 赋值运算符重载)

[3.6 日期类实现](#3.6 日期类实现)

[3.7 const成员函数](#3.7 const成员函数)

[3.8 取地址运算符重载](#3.8 取地址运算符重载)

第四部分:类和对象(下)

[4.1 再探构造函数(初始化列表)](#4.1 再探构造函数(初始化列表))

[4.2 类型转换](#4.2 类型转换)

[4.3 static成员](#4.3 static成员)

[4.4 友元](#4.4 友元)

[4.5 内部类](#4.5 内部类)

[4.6 匿名对象](#4.6 匿名对象)

[4.7 对象拷贝时的编译器优化](#4.7 对象拷贝时的编译器优化)

结语



第一部分:C++入门基础

1.1 C++简介与发展历史

C++的起源可以追溯到1979年,当时Bjarne Stroustrup在贝尔实验室面对复杂软件开发任务时,感受到了C语言在表达能力、可维护性和可扩展性方面的不足。1983年,他在C语言的基础上添加了面向对象编程的特性,设计出了C++语言的雏形,正式命名为C++。

重要里程碑:

  • 1983年:C++诞生,支持类、封装、继承等核心概念

  • 1998年:C++98标准发布,第一个官方标准版本

  • 2011年:C++11发布,革命性更新,增加大量新特性

  • 2020年:C++20发布,引入协程、概念、模块化等现代特性

1.2 C++版本演进

版本 发布时间 主要特性
C++98 1998年 第一个官方标准,引入STL
C++03 2003年 修复错误,引入tr1库
C++11 2011年 lambda、右值引用、智能指针、线程库
C++14 2014年 泛型lambda、二进制字面量
C++17 2017年 if constexpr、折叠表达式
C++20 2020年 协程、概念、模块化
C++23 2023年 if consteval、flat_map

1.3 C++的重要性与应用领域

根据TIOBE 2024年6月的排行榜,C++稳居前三,广泛应用于:

  1. 游戏开发:Unreal Engine等游戏引擎

  2. 操作系统:Windows、Linux内核

  3. 嵌入式系统:智能设备、车载系统

  4. 机器学习引擎:TensorFlow底层

  5. 金融系统:高频交易平台

  6. 音视频处理:FFmpeg、WebRTC

  7. 服务器端开发:高性能后台服务

1.4 C++学习建议与书籍推荐

学习建议:

  1. 先动手再理论,从写代码开始

  2. 循序渐进,每天掌握1-2个概念

  3. 善用文档和社区资源

推荐书籍:

  • 《C++ Primer》:语法大全,适合作为参考书

  • 《Effective C++》:教你写出更好的C++代码

  • 《STL源码剖析》:深入理解标准库实现

1.5 第一个C++程序

cpp

复制代码
#include <iostream>  // 输入输出库
using namespace std; // 使用标准命名空间

int main() {         // 程序入口
    cout << "Hello, C++ World!" << endl;
    return 0;
}

1.6 命名空间(Namespace)

解决命名冲突的利器,特别是大型项目中。

cpp

复制代码
namespace CompanyA {
    int add(int a, int b) { return a + b; }
}

namespace CompanyB {
    int add(int a, int b) { return a + b + 10; }
}

int main() {
    cout << CompanyA::add(1, 2) << endl;  // 输出3
    cout << CompanyB::add(1, 2) << endl;  // 输出13
    return 0;
}

1.7 输入输出

C++提供了更安全、更方便的输入输出方式:

cpp

复制代码
#include <iostream>
using namespace std;

int main() {
    int a;
    double b;
    char c;
    
    // 输入
    cin >> a >> b >> c;
    
    // 输出
    cout << a << " " << b << " " << c << endl;
    
    return 0;
}

1.8 缺省参数(默认参数)

让函数调用更灵活,减少重复代码:

cpp

复制代码
// 全缺省
void greet(string name = "World", string punctuation = "!") {
    cout << "Hello, " << name << punctuation << endl;
}

// 半缺省(必须从右向左连续)
void logMessage(string message, int level = 1, bool timestamp = true) {
    // ...
}

1.9 函数重载(Overload)

同一函数名,不同参数列表,让代码更直观:

cpp

复制代码
void print(int value) {
    cout << "整数: " << value << endl;
}

void print(double value) {
    cout << "浮点数: " << value << endl;
}

void print(string str) {
    cout << "字符串: " << str << endl;
}

1.10 引用(Reference)

引用是变量的别名,共享同一内存空间:

cpp

复制代码
int main() {
    int original = 42;
    int& alias = original;  // alias是original的别名
    
    alias = 100;            // 修改alias就是修改original
    cout << original << endl;  // 输出100
    
    return 0;
}

1.11 内联函数(Inline)

用空间换时间,适合短小频繁调用的函数:

cpp

复制代码
inline int square(int x) {
    return x * x;
}

int main() {
    int result = square(5);  // 编译器可能会展开为 5 * 5
    cout << result << endl;  // 输出25
    return 0;
}

1.12 nullptr

更安全、更明确的空指针表示:

cpp

复制代码
int* ptr = nullptr;  // 推荐!明确表示空指针
int* ptr2 = NULL;    // 可能被定义为0,可能引起歧义

第二部分:类和对象(上)

2.1 类的定义

类是将数据和操作数据的方法封装在一起的用户自定义数据类型:

cpp

复制代码
class Date {
public:
    // 成员函数
    void Init(int year, int month, int day) {
        _year = year;
        _month = month;
        _day = day;
    }
    
    void Print() {
        cout << _year << "/" << _month << "/" << _day << endl;
    }

private:
    // 成员变量
    int _year;
    int _month;
    int _day;
};

2.2 访问限定符

C++通过访问限定符实现封装:

  • public:公有成员,类外可以直接访问

  • private:私有成员,只能在类内访问

  • protected:保护成员,类内和派生类中可以访问

cpp

复制代码
class Stack {
public:      // 公有成员,对外提供接口
    void Push(int x);
    int Top();
    
private:     // 私有成员,外部无法直接访问
    int* _array;
    size_t _capacity;
    size_t _top;
};

2.3 类域

类定义了一个新的作用域,类的所有成员都在类的作用域中:

cpp

复制代码
class Stack {
public:
    void Init(int n = 4);  // 声明
private:
    int* _array;
};

// 定义需要指定类域
void Stack::Init(int n) {
    _array = (int*)malloc(sizeof(int) * n);
    // ...
}

2.4 实例化

用类类型创建对象的过程称为实例化:

cpp

复制代码
int main() {
    Date d1;           // 实例化对象d1
    Date d2;           // 实例化对象d2
    
    d1.Init(2024, 3, 31);
    d2.Init(2024, 7, 5);
    
    return 0;
}

2.5 对象大小

对象大小由成员变量决定,遵循内存对齐规则:

cpp

复制代码
class A {
private:
    char _ch;    // 1字节
    int _i;      // 4字节,对齐到4的倍数
};

int main() {
    A a;
    cout << sizeof(a) << endl;  // 输出8(1+3填充+4)
    return 0;
}

2.6 this指针

编译器为每个成员函数隐式添加this指针,指向调用该函数的对象:

cpp

复制代码
class Date {
public:
    // 编译器转换为:void Init(Date* const this, int year, int month, int day)
    void Init(int year, int month, int day) {
        this->_year = year;  // 通过this指针访问成员
        _month = month;      // 等价于this->_month
        _day = day;
    }
};

2.7 C++与C实现Stack的对比

C语言实现Stack:

c

复制代码
typedef struct Stack {
    int* a;
    int top;
    int capacity;
} ST;

void STInit(ST* ps);
void STPush(ST* ps, int x);

C++实现Stack:

cpp

复制代码
class Stack {
public:
    void Init(int n = 4);
    void Push(int x);
    int Top();
    
private:
    int* _a;
    size_t _top;
    size_t _capacity;
};

主要改进:

  1. 数据和函数封装在类中

  2. 通过访问限定符控制访问权限

  3. 成员函数自动传递this指针

  4. 支持缺省参数等现代特性


第三部分:类和对象(中)

3.1 类的默认成员函数概述

C++为每个类自动生成6个默认成员函数:

  1. 构造函数

  2. 析构函数

  3. 拷贝构造函数

  4. 赋值运算符重载

  5. 取地址运算符重载

  6. const取地址运算符重载

3.2 构造函数

构造函数在对象创建时自动调用,用于初始化对象:

cpp

复制代码
class Date {
public:
    // 默认构造函数(无参)
    Date() {
        _year = 1;
        _month = 1;
        _day = 1;
    }
    
    // 带参构造函数
    Date(int year, int month, int day) {
        _year = year;
        _month = month;
        _day = day;
    }
    
    // 全缺省构造函数(也是默认构造函数)
    Date(int year = 1, int month = 1, int day = 1) {
        _year = year;
        _month = month;
        _day = day;
    }
};

重要规则:

  • 默认构造函数、无参构造函数、全缺省构造函数只能存在一个

  • 不写构造函数时,编译器会自动生成默认构造函数

  • 编译器生成的默认构造函数对内置类型不处理,对自定义类型调用其默认构造函数

3.3 析构函数

析构函数在对象销毁时自动调用,用于清理资源:

cpp

复制代码
class Stack {
public:
    Stack(int n = 4) {
        _a = (int*)malloc(sizeof(int) * n);
        _capacity = n;
        _top = 0;
    }
    
    ~Stack() {      // 析构函数
        free(_a);
        _a = nullptr;
        _top = _capacity = 0;
    }
};

特点:

  1. 函数名是类名前加~

  2. 无参数无返回值

  3. 一个类只能有一个析构函数

  4. 局部对象后定义先析构

3.4 拷贝构造函数

用于使用已有对象初始化新对象:

cpp

复制代码
class Date {
public:
    // 拷贝构造函数
    Date(const Date& d) {  // 必须使用const引用
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }
};

重要规则:

  1. 拷贝构造函数是构造函数的重载

  2. 参数必须是类类型对象的引用

  3. 编译器默认生成的拷贝构造函数完成浅拷贝

  4. 有资源管理的类必须自定义拷贝构造函数(深拷贝)

浅拷贝与深拷贝示例:

cpp

复制代码
// 浅拷贝(默认)
Stack st1;
Stack st2 = st1;  // st2._a和st1._a指向同一块内存

// 深拷贝(自定义)
Stack(const Stack& st) {
    _a = (int*)malloc(sizeof(int) * st._capacity);
    memcpy(_a, st._a, sizeof(int) * st._top);
    _capacity = st._capacity;
    _top = st._top;
}

3.5 赋值运算符重载

用于两个已存在对象间的赋值:

cpp

复制代码
class Date {
public:
    Date& operator=(const Date& d) {
        // 防止自己给自己赋值
        if (this != &d) {
            _year = d._year;
            _month = d._month;
            _day = d._day;
        }
        return *this;  // 支持连续赋值
    }
};

特点:

  1. 必须重载为成员函数

  2. 参数建议使用const引用

  3. 返回值建议使用引用(支持连续赋值)

  4. 编译器默认生成的赋值运算符完成浅拷贝

3.6 日期类实现

完整的日期类示例:

cpp

复制代码
class Date {
public:
    Date(int year = 1900, int month = 1, int day = 1);
    
    // 关系运算符重载
    bool operator<(const Date& d) const;
    bool operator==(const Date& d) const;
    
    // 算术运算符重载
    Date& operator+=(int day);
    Date operator+(int day) const;
    
    // 前置++和后置++
    Date& operator++();
    Date operator++(int);
    
    // 日期相减
    int operator-(const Date& d) const;
    
private:
    int _year;
    int _month;
    int _day;
    
    int GetMonthDay(int year, int month) const;
};

3.7 const成员函数

const成员函数承诺不修改对象状态:

cpp

复制代码
class Date {
public:
    // const成员函数
    void Print() const {  // 相当于 const Date* const this
        // _year = 2024;  // 错误!不能修改成员
        cout << _year << "-" << _month << "-" << _day << endl;
    }
    
    int GetYear() const { return _year; }
};

重要:

  1. const对象只能调用const成员函数

  2. 非const对象可以调用const成员函数(权限缩小)

  3. const成员函数不能调用非const成员函数

3.8 取地址运算符重载

一般不需要自定义,除非特殊需求:

cpp

复制代码
class Date {
public:
    Date* operator&() {
        return this;  // 正常返回地址
        // return nullptr;  // 特殊:不让别人取地址
    }
    
    const Date* operator&() const {
        return this;
    }
};

第四部分:类和对象(下)

4.1 再探构造函数(初始化列表)

初始化列表是成员变量初始化的最佳方式:

cpp

复制代码
class Date {
public:
    // 使用初始化列表
    Date(int year, int month, int day)
        : _year(year)      // 直接初始化
        , _month(month)
        , _day(day)
        , _ref(year)       // 引用成员必须在初始化列表初始化
        , _n(10)           // const成员必须在初始化列表初始化
    {
        // 函数体内是赋值,不是初始化
    }

private:
    int _year;
    int _month;
    int _day;
    int& _ref;     // 引用成员
    const int _n;  // const成员
};

初始化列表规则:

  1. 每个成员变量在初始化列表中只能出现一次

  2. 引用成员、const成员、没有默认构造的自定义类型成员必须在初始化列表初始化

  3. 初始化顺序按成员声明顺序,与初始化列表中的顺序无关

  4. C++11支持在声明处给缺省值

4.2 类型转换

C++支持内置类型到类类型的隐式转换:

cpp

复制代码
class A {
public:
    A(int a) : _a(a) {}  // 转换构造函数
    
    // 加explicit禁止隐式转换
    // explicit A(int a) : _a(a) {}
};

int main() {
    A a = 10;  // 隐式转换:10 -> A(10) -> 调用拷贝构造(编译器优化为直接构造)
    return 0;
}

4.3 static成员

static成员属于类,不属于任何对象:

cpp

复制代码
class A {
public:
    A() { ++_count; }        // 构造时计数
    ~A() { --_count; }       // 析构时计数
    
    static int GetCount() {  // 静态成员函数
        return _count;
    }
    
private:
    static int _count;  // 静态成员变量声明
};

// 静态成员变量定义(必须在类外)
int A::_count = 0;

int main() {
    A a1, a2;
    cout << A::GetCount() << endl;  // 输出2
    return 0;
}

特点:

  1. 静态成员变量在类外定义和初始化

  2. 静态成员函数没有this指针,只能访问静态成员

  3. 可以通过类名或对象访问静态成员

  4. 静态成员受访问限定符限制

4.4 友元

友元打破封装,允许外部访问私有成员:

cpp

复制代码
class Date;  // 前置声明

// 友元函数
class Time {
    friend void PrintDateTime(const Date& d, const Time& t);
private:
    int _hour;
    int _minute;
};

class Date {
    friend void PrintDateTime(const Date& d, const Time& t);
    friend class Time;  // 友元类:Time的所有成员函数都是Date的友元
private:
    int _year;
    int _month;
    int _day;
};

void PrintDateTime(const Date& d, const Time& t) {
    // 可以访问Date和Time的私有成员
    cout << d._year << "-" << d._month << "-" << d._day << " "
         << t._hour << ":" << t._minute << endl;
}

注意:

  1. 友元关系是单向的

  2. 友元关系不能传递

  3. 友元破坏了封装,应谨慎使用

4.5 内部类

类中定义的类称为内部类:

cpp

复制代码
class Outer {
private:
    static int _outer_static;
    int _outer_value = 10;
    
public:
    class Inner {  // Inner默认是Outer的友元
    public:
        void VisitOuter(const Outer& outer) {
            cout << _outer_static << endl;     // 可以访问Outer的静态成员
            cout << outer._outer_value << endl; // 可以访问Outer的私有成员
        }
    };
};

int Outer::_outer_static = 1;

int main() {
    Outer::Inner inner;  // 通过外部类名访问内部类
    Outer outer;
    inner.VisitOuter(outer);
    return 0;
}

特点:

  1. 内部类独立于外部类,外部类对象不包含内部类

  2. 内部类是外部类的友元类

  3. 内部类受外部类的访问限定符限制

4.6 匿名对象

生命周期只有一行的临时对象:

cpp

复制代码
class A {
public:
    A(int a = 0) : _a(a) {
        cout << "A(int a)" << endl;
    }
    
    ~A() {
        cout << "~A()" << endl;
    }
    
    int GetValue() { return _a; }
};

int main() {
    A();           // 创建匿名对象,本行结束后立即析构
    A(10);         // 带参数的匿名对象
    
    int value = A(20).GetValue();  // 使用匿名对象调用函数
    return 0;
}

4.7 对象拷贝时的编译器优化

现代编译器会优化不必要的拷贝:

cpp

复制代码
class A {
public:
    A(int a = 0) { cout << "A(int a)" << endl; }
    A(const A& a) { cout << "A(const A& a)" << endl; }
    A& operator=(const A& a) { 
        cout << "operator=" << endl; 
        return *this; 
    }
};

A func() {
    A aa;
    return aa;  // 可能被优化:直接构造返回对象,不生成临时对象
}

int main() {
    // 1. 构造+拷贝构造 -> 优化为直接构造
    A a1 = 1;      // 优化:A a1(1)
    
    // 2. 连续拷贝构造 -> 优化为一个拷贝构造
    A a2 = A(2);   // 优化:A a2(2)
    
    // 3. 传值返回优化
    A a3 = func(); // 可能优化:直接在a3的位置构造
    
    return 0;
}

常见优化场景:

  1. 传值传参时,构造+拷贝构造 -> 优化为直接构造

  2. 传值返回时,构造局部对象+拷贝构造临时对象 -> 优化为直接构造返回对象

  3. 连续构造+拷贝构造 -> 优化为一个构造

关闭优化(g++):

bash

复制代码
g++ test.cpp -fno-elide-constructors

结语

C++的类和对象是面向对象编程的基石,理解这些概念对于掌握C++至关重要。从基本的类定义、构造函数、析构函数,到复杂的拷贝控制、运算符重载、友元关系,每个部分都有其独特的设计哲学和实用价值。

学习建议:

  1. 多写代码,实践是理解概念的最佳方式

  2. 理解每个默认成员函数的行为和适用场景

  3. 掌握const的正确用法,写出更安全的代码

  4. 理解编译器优化,但不要依赖特定编译器的优化行为

下一步学习方向:

  1. 继承与多态:面向对象的核心特性

  2. 模板与泛型编程:C++的强大特性

  3. STL标准库:容器、算法、迭代器

  4. 智能指针:现代C++内存管理

  5. 现代C++特性:lambda、移动语义等

记住,学习C++是一场马拉松而非短跑。保持耐心,持续实践,你将逐步掌握这门强大而优雅的语言。祝你编程愉快!

相关推荐
AA陈超27 分钟前
LyraRPG:001.创建RPGCore插件
c++·笔记·学习·ue5·虚幻引擎·lyra
action191628 分钟前
Nano Banana2API国内接入神方案!0.1元/次稳到哭
后端
小李小李快乐不已32 分钟前
图论理论基础(3)
数据结构·c++·算法·图论
lalala_lulu33 分钟前
Lambda表达式是什么
开发语言·python
她说..33 分钟前
Java AOP完全指南:从原理到实战(全套知识点+场景总结)
java·开发语言·spring·java-ee·springboot
Sammyyyyy33 分钟前
Rust性能调优:从劝退到真香
开发语言·后端·rust·servbay
陈鋆34 分钟前
Langchain-Chatchat[三、知识库管理的 RAG]
windows·langchain
Zfox_38 分钟前
【Go】异常处理、泛型和文件操作
开发语言·后端·golang
zhangyanfei0141 分钟前
谈谈 Golang 中的线程协程是如何管理栈内存的
开发语言·后端·golang