当前位置: 首页 > news >正文

C++学习:类和对象(三)

一、深入讲解构造函数

1. 什么是构造函数?

构造函数(Constructor)是在创建对象时自动调用的特殊成员函数,用于初始化对象的成员变量。构造函数的名称与类名相同,没有返回类型

2. 构造函数的类型

(1)默认构造函数

没有参数或所有参数都有默认值的构造函数

class Person {
public:Person() {name = "Unknown";age = 0;}
private:std::string name;int age;
};
(2)有参构造函数

接受参数,用于自定义初始化对象的构造函数

class Person {
public:Person(const std::string& name, int age) : name(name), age(age) {}
private:std::string name;int age;
};
(3)拷贝构造函数

用于创建对象的副本

class Person {
public:Person(const Person& other) : name(other.name), age(other.age) {std::cout << "拷贝构造函数被调用" << std::endl;}
private:std::string name;int age;
};
(4)移动构造函数(C++11 引入)

用于移动资源,避免不必要的拷贝

class Person {
public:Person(Person&& other) noexcept : name(std::move(other.name)), age(other.age) {std::cout << "移动构造函数被调用" << std::endl;}
private:std::string name;int age;
};

3. 构造函数的初始化列表

使用初始化列表可以在构造函数中直接初始化成员,尤其是常量成员或引用类型的成员

class Person {
public:Person(const std::string& name, int age) : name(name), age(age) {}
private:const std::string name;int& age;
};

4. 构造函数的调用顺序

  • 基类构造函数先于派生类构造函数被调用
  • 成员对象的构造函数按照它们在类中声明的顺序被调用

5. 代码示例

#include <iostream>
#include <string>class Address {
public:Address(const std::string& city) : city(city) {std::cout << "Address 构造" << std::endl;}
private:std::string city;
};class Person {
public:Person() : name("Unknown"), age(0), address("Unknown City") {std::cout << "Person 默认构造" << std::endl;}Person(const std::string& name, int age, const std::string& city): name(name), age(age), address(city) {std::cout << "Person 有参构造" << std::endl;}Person(const Person& other): name(other.name), age(other.age), address(other.address) {std::cout << "Person 拷贝构造" << std::endl;}private:std::string name;int age;Address address;
};int main() {Person p1;Person p2("Alice", 30, "New York");Person p3 = p2;return 0;
}

二、深入理解封装

1. 什么是封装?

封装(Encapsulation)是将数据和操作数据的方法绑定在一起,保护对象的内部状态不被外部直接访问和修改。它是面向对象编程的基本特性之一

2. 访问控制符

  • public:公共成员,外部可以访问
  • protected:受保护成员,派生类可以访问
  • private:私有成员,只有类内部可以访问

3. 为什么需要封装?

  • 提高代码的安全性,防止数据被非法访问和修改
  • 隐藏内部实现细节,提供清晰的接口
  • 便于维护和扩展代码

4. 通过方法访问私有成员

class BankAccount {
public:BankAccount(double balance) : balance(balance) {}void deposit(double amount) {if (amount > 0) {balance += amount;}}bool withdraw(double amount) {if (amount > 0 && balance >= amount) {balance -= amount;return true;}return false;}double getBalance() const {return balance;}private:double balance;
};

5. 代码示例

#include <iostream>class Rectangle {
public:void setWidth(double w) {if (w > 0)width = w;}void setHeight(double h) {if (h > 0)height = h;}double getArea() const {return width * height;}private:double width;double height;
};int main() {Rectangle rect;rect.setWidth(10);rect.setHeight(5);std::cout << "面积:" << rect.getArea() << std::endl;return 0;
}

三、static 成员

1. 什么是 static 成员?

在类中,用 static 关键字修饰的成员称为静态成员。它们属于类本身,而不是某个对象

2. 静态成员变量

  • 所有对象共享同一份静态成员变量
  • 必须在类外进行定义和初始化
class Counter {
public:Counter() {++count;}static int getCount() {return count;}private:static int count;
};int Counter::count = 0;

3. 静态成员函数

  • 只能访问静态成员变量和其他静态成员函数
  • 可以在不创建对象的情况下调用
class Math {
public:static double pi() {return 3.14159;}
};

4. 代码示例

#include <iostream>class Student {
public:Student(const std::string& name) : name(name) {++totalStudents;}~Student() {--totalStudents;}static int getTotalStudents() {return totalStudents;}private:std::string name;static int totalStudents;
};int Student::totalStudents = 0;int main() {std::cout << "当前学生人数:" << Student::getTotalStudents() << std::endl;Student s1("Alice");Student s2("Bob");std::cout << "当前学生人数:" << Student::getTotalStudents() << std::endl;{Student s3("Charlie");std::cout << "当前学生人数:" << Student::getTotalStudents() << std::endl;}std::cout << "当前学生人数:" << Student::getTotalStudents() << std::endl;return 0;
}

四、友元(friend

1. 什么是友元?

友元是被类授予访问其私有和保护成员权限的函数或类。使用 friend 关键字声明

2. 友元函数

  • 可以是普通函数或者类的成员函数
  • 在类内声明,在类外定义
class Box {
private:double width;public:friend void setWidth(Box& b, double w);
};void setWidth(Box& b, double w) {b.width = w;
}

3. 友元类

  • 一个类可以将另一个类声明为友元,从而该友元类的成员函数可以访问本类的私有和保护成员
class Engine;class Car {
private:int speed;friend class Engine;
};class Engine {
public:void setSpeed(Car& car, int s) {car.speed = s;}
};

4. 友元的用途

  • 当需要某个函数或类访问另一个类的私有成员时
  • 应谨慎使用,避免破坏封装性

5. 代码示例

#include <iostream>class Secret {
private:std::string password;public:Secret(const std::string& pwd) : password(pwd) {}friend void reveal(const Secret& s);
};void reveal(const Secret& s) {std::cout << "秘密是:" << s.password << std::endl;
}int main() {Secret s("123456");reveal(s);return 0;
}

五、内部类(嵌套类)

1. 什么是内部类?

在一个类的定义中定义另一个类,称为内部类或嵌套类

2. 内部类的特性

  • 内部类可以访问外部类的私有和保护成员
  • 外部类需要通过对象来访问内部类的成员

3. 什么时候使用内部类?

  • 当某个类只为另一个类服务时
  • 为了更好地组织代码,提升封装性

4. 代码示例

#include <iostream>class Outer {
private:int outerData;public:Outer(int data) : outerData(data) {}class Inner {public:void displayOuterData(const Outer& o) {std::cout << "外部类数据:" << o.outerData << std::endl;}};
};int main() {Outer o(100);Outer::Inner i;i.displayOuterData(o);return 0;
}

六、匿名对象

1. 什么是匿名对象?

没有被命名的临时对象,通常在表达式中创建,使用完后立即销毁

2. 匿名对象的用途

  • 作为函数的返回值或参数
  • 进行临时运算

3. 代码示例

#include <iostream>class Number {
public:Number(int value) : value(value) {std::cout << "构造:" << value << std::endl;}~Number() {std::cout << "析构:" << value << std::endl;}int getValue() const {return value;}private:int value;
};Number createNumber(int x) {return Number(x);
}int main() {Number(10); // 创建匿名对象std::cout << "--------" << std::endl;Number n = createNumber(20);std::cout << "n 的值:" << n.getValue() << std::endl;return 0;
}

七、拷贝对象时的一些编译器优化

1. 什么是拷贝消除?

编译器优化的一种,避免不必要的对象拷贝,提高性能

2. 返回值优化(RVO)

当函数返回对象时,直接在调用者的空间构造对象,避免临时对象的生成

class Data {
public:Data() {std::cout << "Data 构造" << std::endl;}Data(const Data&) {std::cout << "Data 拷贝构造" << std::endl;}~Data() {std::cout << "Data 析构" << std::endl;}
};Data getData() {Data d;return d;
}int main() {Data d = getData();return 0;
}

3. 使用 std::move 和移动语义

  • 在需要移动对象而非拷贝时,使用 std::move
#include <vector>
#include <string>int main() {std::vector<std::string> vec;std::string str = "Hello";vec.push_back(std::move(str)); // 移动 str,而不是拷贝return 0;
}

4. 代码示例

#include <iostream>class Example {
public:Example() {std::cout << "构造函数" << std::endl;}Example(const Example&) {std::cout << "拷贝构造函数" << std::endl;}Example(Example&&) noexcept {std::cout << "移动构造函数" << std::endl;}~Example() {std::cout << "析构函数" << std::endl;}
};Example createExample() {Example e;return e;
}int main() {Example e = createExample();return 0;
}

http://www.lryc.cn/news/473682.html

相关文章:

  • 高阶数据结构--图(graph)
  • xxl-job java.sql.SQLException: interrupt问题排查
  • jmeter压测工具环境搭建(Linux、Mac)
  • docker设置加速
  • 使用requestAnimationFrame写防抖和节流
  • Puppeteer 与浏览器版本兼容性:自动化测试的最佳实践
  • Java方法重写
  • vscode通过.vscode/launch.json 内置php服务启动thinkphp 应用后无法加载路由解决方法
  • Webserver(2.6)有名管道
  • 四足机器人实战篇之一:波士顿spot机器人工程实现分析
  • TensorFlow 预训练目标检测模型集合
  • 字符串的区别
  • EMR Serverless Spark:一站式全托管湖仓分析利器
  • Linux find 匹配文件内容
  • 【Redis优化——如何优雅的设计key,优化BigKey,Pipeline批处理Key】
  • 数据结构与算法分析:你真的理解图算法吗——深度优先搜索(代码详解+万字长文)
  • LinkedList 分析
  • 【C/C++】模拟实现strlen
  • mybatis从浅入深一步步演变分析
  • Java阶段三02
  • 【Linux】掌握库的艺术:我的动静态库封装之旅
  • UE5动画控制 基础
  • 流畅!HTMLCSS打造网格方块加载动画
  • linux命令之top(Linux Command Top)
  • 数据结构-希尔排序(ShellSort)笔记
  • Junit + Mockito保姆级集成测试实践
  • 软件项目管理要点
  • ESP8266 连接 MQTT 服务器EMQX 连接MQTTX
  • Python中如何处理异常情况?
  • openpnp - 在openpnp中单独测试相机