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

商贸城网站建设方案手机网站运营

商贸城网站建设方案,手机网站运营,可以接外包的网站,wordpress给图片加链接地址1.1QT介绍 1.1.1 QT简介 Qt 是一个跨平台的应用程序和用户界面框架#xff0c;用于开发图形用户界面#xff08;GUI#xff09;应用程序以及命令行工具。它最初由挪威的 Trolltech #xff08;奇趣科技#xff09;公司开发#xff0c;现在由 Qt Company 维护#xff…1.1QT介绍 1.1.1 QT简介 Qt 是一个跨平台的应用程序和用户界面框架用于开发图形用户界面GUI应用程序以及命令行工具。它最初由挪威的 Trolltech 奇趣科技公司开发现在由 Qt Company 维护2020年12月8日发布QT6。Qt 使用 C 语言编写支持多种编程语言通过绑定进行使用。 1.1.2 QT Creator 常用的快捷键使用基本介绍 2.1 命名空间 2.1.1命名空间作用 创建自己的命名空间是 C 中组织代码的一种好方法特别是在开发大型项目或库时。命名空间可以帮助你避免名称冲突并且清晰地组织代码。 std 是 C 标准库的命名空间。它是一个定义在 C 标准库中的所有类、函数和变量的命名空间。 在 C 中如果你想使用标准库中的任何类、函数或对象你通常有两种选择 1. 使用 std:: 前缀这是最常见的方式它明确指定了你正在使用的是位于 std 命名空间中的元 素。 std::cout Hello, world! std::endl; 2. 使用 using namespace std; 这允许你在不显式指定 std:: 的情况下使用 std 命名空间中的 所有元素。 using namespace std; cout Hello, world! endl; std包含的内容 std 命名空间包含了许多类、函数和对象例如 输入输出库如 std::cout , std::cin , std::endl 容器类如 std::vector , std::map , std::set 字符串类 std::string 异常类 std::exception 和相关子类 算法如 std::sort , std::find 实用工具如 std::pair , std::tuple 其他许多功能 使用建议 对于小型代码或示例代码使用 using namespace std; 通常是安全的。 对于大型项目或库建议显式地使用 std:: 前缀以避免潜在的名称冲突并提高代码的可读性 和可维护性。 std 命名空间是 C 编程的基础部分理解和正确使用它对于编写健壮和高效的 C 代码至关重要。 2.1.2自定义命名空间 定义命名空间 假设我们要创建一个命名空间来包含与圆形相关的功能。我们可以命名这个命名空间为 cir 在这个头文件中我们定义了一个名为 cir 的命名空间其中包含了计算圆的面积和周长的函数以及圆周率常量 PI 。 使用命名空间 在另一个文件中我们可以使用这个命名空间中定义的函数和常量 在 main.cpp 中我们首先包含了定义 Cir 命名空间的头文件。然后我们可以使用 Cir:: 前缀来访 问该命名空间中的函数和常量。 通过使用自定义命名空间你可以有效地组织你的代码并减少不同库之间的名称冲突。这在大型项目和团队协作中尤其重要。 输出结果 2.2 从C语言快速入门 2.2.1 输入输出 C 中的输入和输出I/O主要是通过标准库中的输入输出流来实现的。最常用的是 iostream 库它提供了用于输入和输出的基本流类包括 cin 、 cout 、 cerr 和 clog 。 标准输出流 ( cout ) cout 代表标准输出流通常用于向屏幕输出数据。 使用操作符 插入操作符向 cout 发送数据。 例如 std::cout Hello, world! std::endl; 会在屏幕上打印 Hello, world! 并换行。 标准输入流 ( cin ) cin 代表标准输入流用于从键盘接收数据。 使用操作符 提取操作符从 cin 提取数据。 例如 int x; std::cin x; 会从用户那里读取一个整数并存储在变量 x 中。 标准错误流 ( cerr ) 和标准日志流 ( clog ) cerr 用于输出错误消息。与 cout 不同 cerr 不是缓冲的这意味着它会立即输出。 clog 类似于 cerr 但它是缓冲的。它通常用于记录错误和日志信息。 2.2.2 基本变量类型 C 基本数据类型整理成表格。以下是一个表格展示了不同的基本数据类型及其一般用途和大小范围 和C语言类似。 2.2.3 内联函数 内联函数Inline Function是C中一种特殊的函数其定义直接在每个调用点展开。这意味着编译器会尝试将函数调用替换为函数本身的代码这样可以减少函数调用的开销尤其是在小型函数中。 特点 1. 减少函数调用开销内联函数通常用于优化小型、频繁调用的函数因为它避免了函数调用的常规开销如参数传递、栈操作等。 2. 编译器决策即使函数被声明为内联编译器也可能决定不进行内联特别是对于复杂或递归函 数。 3. 适用于小型函数通常只有简单的、执行时间短的函数适合做内联。 4. 定义在每个使用点内联函数的定义而非仅仅是声明必须对每个使用它的文件都可见通常意味着将内联函数定义在头文件中。 使用方法 通过在函数声明前添加关键字 inline 来指示编译器该函数适合内联 inline int max(int x, int y) {         return x y ? x : y; } 示例 #include iostream inline int add(int a, int b) {         return a b; } int main() {         int result add(5, 3); // 编译器可能会将此替换为int result 5 3;         std::cout Result: result std::endl;         return 0; } 在这个示例中函数 add 被定义为内联函数。当它被调用时编译器可能会将函数调用替换为函数体内的代码。 注意事项 过度使用的风险不应滥用内联函数因为这可能会增加最终程序的大小代码膨胀。对于大型 函数或递归函数内联可能导致性能下降。 编译器的决定最终是否将函数内联是由编译器决定的即使函数被标记为 inline 。 适用场景最适合内联的是小型函数和在性能要求高的代码中频繁调用的函数。 内联函数是一种用于优化程序性能的工具但需要合理使用以确保代码的可维护性和性能的平衡。 2.2.4 Lambda 表达式 Lambda 表达式是 C11 引入的一种匿名函数的方式它允许你在需要函数的地方内联地定义函数而无需单独命名函数 Lambda 表达式的基本语法如下 [capture clause](parameters) - return_type {         // 函数体         // 可以使用捕获列表中的变量         return expression; // 可选的返回语句 } Lambda 表达式由以下部分组成 捕获列表Capture clause用于捕获外部变量在 Lambda 表达式中可以访问这些变量。捕 获列表可以为空也可以包含变量列表 [var1, var2, ...] 。 参数列表Parameters与普通函数的参数列表类似可以为空或包含参数列表 (param1, param2, ...) 。 返回类型Return typeLambda 表达式可以自动推断返回类型auto也可以显式指定返回类 型 - return_type 。如果函数体只有一条返回语句可以省略返回类型。 函数体BodyLambda 表达式的函数体包含需要执行的代码。 Lambda 表达式最简单的案例是在需要一个小型函数或临时函数时直接使用它。以下是一个非常简单的例子其中使用 Lambda 表达式来定义一个加法操作并立即使用它来计算两个数的和。 #include iostream int main() {         // 定义一个简单的 Lambda 表达式进行加法         auto add [ ](int a, int b)         {                 return a b;         };         // 使用 Lambda 表达式计算两个数的和         int sum add(10, 20);         std::cout Sum is: sum std::endl;         return 0; } 在这个例子中 我们定义了一个名为 add 的 Lambda 表达式它接受两个整数参数并返回它们的和。然后我们使用这个 Lambda 表达式来计算两个数字10 和 20的和并将结果存储在变量 sum中。最后我们打印出这个和。 这个例子展示了 Lambda 表达式的基本用法作为一种简洁而快速的方式来定义小型函数。 我们可以写一个例子其中使用一个函数来找出两个数中的较大数这个函数将接受一个 lambda 函数作为回调来比较这两个数。Lambda 函数将直接在函数调用时定义完全是匿名的。 先回忆以下回调函数 #include iostream bool myCompare(int a, int b) {         return a b; } int getMax( int a, int b, bool (*compare)(int, int) ) {         if (compare(a, b))          {                 return a;         } else         {                 return b;         } } int main() {         int x 10;         int y 20;         // 回调函数         int max getMax(x, y, myCompare);         std::cout The larger number is: max std::endl;         return 0; } 示例使用匿名 Lambda 函数来返回两个数中的较大数 #include iostream // 函数接受两个整数和一个比较的 lambda 函数 int getMax(int a, int b, bool(*compare)(int, int)) {         if (compare(a, b))         {                 return a;         } else          {                 return b;         } } int main() {         int x 10;         int y 20;         // 直接在函数调用中定义匿名 lambda 函数         int max getMax(x, y, [ ](int a, int b) - bool         {                 return a b;         });         std::cout The larger number is: max std::endl;         return 0; } 在这个例子中 getMax 函数接受两个整数 a 和 b 以及一个比较函数 compare 。这个比较函数是一个指向函数 的指针它接受两个整数并返回一个布尔值。在 main 函数中我们调用 getMax 并直接在调用点定义了一个匿名的 lambda 函数。这个lambda 函数接受两个整数并返回一个表示第一个整数是否大于第二个整数的布尔值。这个 lambda 函数在 getMax 中被用作比较两个数的逻辑。根据 lambda 函数的返回值 getMax返回较大的数。 这个例子展示了如何直接在函数调用中使用匿名 lambda 函数使代码更加简洁和直接。这种方法在需要临时函数逻辑的场合非常有用尤其是在比较、条件检查或小型回调中。 在 Lambda 表达式中参数捕获是指 Lambda 表达式从其定义的上下文中捕获变量的能力。这使得Lambda 可以使用并操作在其外部定义的变量。捕获可以按值拷贝或按引用进行。 让我们通过一个简单的示例来展示带参数捕获的 Lambda 表达式。 输出 在这个例子中 第一个 Lambda 表达式 sum 按值捕获了 x 和 y 即它们的副本。这意味着 sum 内的 x 和 y 是在 Lambda 定义时的值的拷贝。 第二个 Lambda 表达式 mul 使用 [] 捕获列表这表示它按值捕获所有外部变量。 第三个 Lambda 表达式 modify_mul 使用 [] 捕获列表这表示它按引用捕获所有外部变量。因此它可以修改 x 和 y 的原始值。 这个示例展示了如何使用不同类型的捕获列表按值和按引用来控制 Lambda 表达式对外部变量的访问和修改。按值捕获是安全的但不允许修改原始变量而按引用捕获允许修改原始变量但需要注意引用的有效性和生命周期问题。 以下是一个表格概述了 Lambda 函数和内联函数在 C 中的相似之处和区别 请注意虽然 Lambda 函数和内联函数在某些方面有相似之处如它们都可以被编译器优化以减少调用开销但它们在设计和用途上有明显的不同。Lambda 函数的核心优势在于它们的匿名性和对外部变量的捕获能力而内联函数则主要关注于提高小型函数的性能。 2.3类 2.3.1 类的初探 C 中的类class是一种编程结构用于创建对象。这些对象可以拥有属性即数据成员和行为即成员函数或方法。类的概念是面向对象编程的核心之一其主要目的是将数据和与数据相关的操作封装在一起。例如如果你有一个“汽车”类它可能包含颜色、品牌、型号等属性数据成员以及启动、停止、加速等行为成员函数。每当你基于这个类创建一个对象时你就有了一个具体的汽车具有这些属性和行为。 C 类的基本结构通常包含 1. 数据成员Attributes定义类的属性。这些是类内部的变量用于存储对象的状态。 2. 成员函数Methods定义类的行为。这些是可以操作对象的数据成员的函数。 3. 构造函数和析构函数特殊的成员函数。构造函数在创建对象时自动调用用于初始化对象。析构函数在对象销毁时调用用于执行清理操作。 4. 访问修饰符如 public , private , protected 用于控制对类成员的访问权限。例如 public成员可以在类的外部访问而 private 成员只能在类内部访问。 5. 继承允许一个类继承另一个类的特性。这是代码重用和多态性的关键。 通过这些特性C 类提供了一种强大的方式来组织和处理数据使得代码更加模块化、易于理解和维护。 2.3.2 结构体引入类 2.3.2.1 回忆结构体 如果用C语言实现上面描述的汽车类我们实现如下代码 输出 2.3.2.2 新建C工程来使用结构体 在C中字符串用string来表示发现有个string赋值给char 的警告所以修改所有char *为 string类型 main . cpp : 33 : 17 : warning : ISO C 11 does not allow conversion from string literal to char * 修改后发现printf的%s控制位不能用于string的输出所有有string构建了即将要输出的字符串 C中通过std::tostring()函数将整型数转化成字符串 在printCarInfo中使用cout输出汽车信息 发现在C工程中使用malloc在堆申请结构体空间有问题所以直接在此引入类的概念把struct改成class 引入新问题class的成员数据和成员函数在不指定权限的情况下默认private权限类的对象无法进行直接访问 main.cpp:33:9: error: color is a private member of Car main.cpp:5:11: note: implicitly declared private here 添加public属性 把main函数中的原本结构体变量改成了类的实例化如果变量类型是指针把原来的malloc改成 new一个对象 最后解决了所有问题 但是我们还没有真正体验到面向对象的封装特性仅仅感受到权限上的区别 2.3.2.3 真正的成员函数 上一节的案例中 void (*printCarInfo)(string color,string brand,string type, int year); 到底是变量函数还是成员函数呢 答是一个指针变量是保存某个函数地址的变量所以它不是成员函数是成员数据 真正的成员函数遵守封装特性在函数体内部访问成员数据的时候不需要参数传递 在 C 中双冒号 :: 称为 作用域解析运算符Scope Resolution Operator。它用于指定一 个成员如函数或变量属于特定的类或命名空间。例如在类的外部定义成员函数时 :: 用于 指明该函数属于哪个类。 2.3.4 QT中经常出现的用法 在 C中一个类包含另一个类的对象称为组合Composition。这是一种常见的设计模式用 于表示一个类是由另一个类的对象组成的。这种关系通常表示一种拥有has-a的关系。 普通变量访问成员变量或者成员函数使用 “ . ” 运算符 指针变量访问成员变量或者成员函数使用“ - ”运算符像C语言的结构体用法 输出 2.4 权限初识 2.4.1 基本介绍 C中的访问权限主要分为三种 public 、 private 和 protected 。这些权限决定了类成员包括数据成员和成员函数的可访问性。以下是一个总结表格说明了在不同情况下这些权限如何应用 使用权限如 public 、 private 和 protected 在C中是一种关键的封装手段它们旨在控制对类成员的访问。下面是一个表格总结了使用权限的主要好处和潜在缺点 2.4.2 目前能概况的结论 public 权限相当于我们学习C语言结构体一样不考虑访问权限的存在但是要注意类中不写权 限默认是私有权限 protected 留到继承讲解的时候再提 private 私有权限通过一下案例向各位表达一下作用的意思但需要未来实战中慢慢体会。 这个例子将阐述在类设计中使用 private 成员的必要性。我们将创建一个简单的 BankAccount 类展示如何使用 private 来保护账户的余额确保它只能通过指定的方法进行修改。 所以我们可以脑部一个场景 银行的账户是一个模板是一个类有存款人信息和账户额度而具体的存款人视为一个对象一个对象不能私自修改账户额度需要通过一个操作流程比如去ATM或者柜台进行操作才能修改到账户额度所以存款人信息和账户额度设计成私有权限通过公有的操作流程也就是公有函数去操作私有变量。 基于这个场景我们编程实现代码 输出 在这个示例中 balance 是一个 private 成员变量它不能被类的外部直接访问。这保证了账户余额只能通过类提供的方法如 putinMoney , getfromMoney, 和 getBalance 来修改和查询从而防止了不合适的修改比如直接设置余额为负数或任意值。这样的设计保证了类的封装性和数据的完整性。 2.4.3 提问和回答 问为什么新手学习C感受不到访问权限的必要性呢? 答新手学习C时可能不会立即感受到访问权限如 public 、 private 、 protected 的必要性主要有以下几个原因 1. 简单的例子和练习初学者通常从简单的例子和练习开始这些例子可能不需要复杂的封装或继承结构。在这种情况下访问权限的作用可能不太明显。 2. 封装的概念需要时间去理解封装是面向对象编程中的一个核心概念但对于初学者来说理解封装的价值需要一定的时间和实践。在初期更多的关注点可能放在基本语法和程序结构上。 3. 缺乏大型项目经验在小型项目或单文件程序中访问权限的重要性可能不如在大型、多人协作的项目中那么显著。在复杂的软件开发中适当的访问控制对于代码的维护性和可读性至关重要。 4. 直接操作感觉更简单对于初学者来说直接访问和修改类的所有成员可能看起来更简单直接。他们可能还没有遇到由于不恰当访问控制导致的维护和调试问题。 5. 抽象和设计模式的理解理解何时以及如何使用访问权限通常涉及到对软件设计模式和抽象的深入理解。这些通常是随着经验积累和更深入的学习而逐渐掌握的。 随着经验的增长学习者开始处理更复杂的项目他们将开始意识到恰当的访问控制的重要性特别是在保持代码的可维护性、可读性以及在团队环境中的协作方面。因此对于教育者和学习者来说强调并实践这些概念是很重要的以便在编程技能成熟时能够有效地运用它们。 2.5 引用 引用变量是一个别名也就是说它是某个已存在变量的另一个名字。 一旦把引用初始化为某个变量就可以使用该引用名称或变量名称来指向变量。 思维发散: 在C语言中一个数据对应一个内存通过由一个变量名来访问这个内存空间的数据叫做直接访问相对直接访问有个间接访问的说法叫做指针。 而引用相当于又给这个内存中的数据提供了一个新的变量名 这个变量名功能比传统变量名更特殊是直达地址的后续代码验证 2.5.1 和指针的区别 引用很容易与指针混淆它们之间有三个主要的不同 1.不存在空引用。引用必须连接到一块合法的内存。 2.一旦引用被初始化为一个对象就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。 3.引用必须在创建时被初始化。指针可以在任何时间被初始化。 官方没有明确说明但是引用确实不是传统意义上的独立变量它不能“变”嘛 试想变量名称是变量附属在内存位置中的标签可以把引用当成是变量附属在内存位置中的第二 个标签。因此可以通过原始变量名称或引用来访问变量的内容。例如 int i 17 ; int* p i ; * p 20 ; 我们可以为 i 声明引用变量如下所示 int r i; double s d; 在这些声明中 读作引用。 因此第一个声明可以读作 r 是一个初始化为 i 的整型引用第二个声明可以读作 s 是一个初始化为 d 的 double 型引用。 下面的实例使用了 int 和 double 引用 输出 2.5.2 把引用作为参数 我们已经讨论了如何使用指针来实现引用调用函数。下面的实例使用了引用来实现引用调用函数。 输出 2.5.3 把引用作为返回值 通过使用引用来替代指针会使 C 程序更容易阅读和维护。C 函数可以返回一个引用方式与返回一个指针类似。 当函数返回一个引用时则返回一个指向返回值的隐式指针。 这样函数就可以放在赋值语句的左边。 例如请看下面这个简单的程序 输出 2.6 重载 2.6.1 函数重载 在同一个作用域内可以声明几个功能类似的同名函数这些同名函数的形式参数指参数的个数、类型或者顺序必须不同。不能仅通过返回类型的不同来重载函数。 下面的实例中同名函数 print() 被用于输出不同的数据类型 输出 2.7 构造函数 2.7.1 什么是构造函数 类的构造函数是类的一种特殊的成员函数它会在每次创建类的新对象时执行。 构造那构造的是什么呢 构造成员变量的初始化值内存空间等 构造函数的名称与类的名称是完全相同的并且不会返回任何类型也不会返回 void。构造函数可用于为某些成员变量设置初始值。 2.7.2 带参数构造函数 默认的构造函数没有任何参数但如果需要构造函数也可以带有参数。这样在创建对象时就会给对象赋初始值 下面的实例有助于更好地理解构造函数的概念 输出 2.7.3 使用初始化列表 在C中使用初始化列表来初始化类的字段是一种高效的初始化方式尤其在构造函数中。初始化列表直接在对象的构造过程中初始化成员变量而不是先创建成员变量后再赋值。这对于提高性能尤其重要特别是在涉及到复杂对象或引用和常量成员的情况下。 初始化列表紧跟在构造函数参数列表后面以冒号 : 开始后跟一个或多个初始化表达式每个表达式通常用逗号分隔。下面是使用初始化列表初始化字段的例子 输出 初始化列表的优点包括 1. 效率对于非基本类型的对象使用初始化列表比在构造函数体内赋值更高效因为它避免了先默认构造然后再赋值的额外开销。 2. 必要性对于引用类型和常量类型的成员变量必须使用初始化列表因为这些类型的成员变量在构造函数体内不能被赋值。 3. 顺序成员变量的初始化顺序是按照它们在类中声明的顺序而不是初始化列表中的顺序。 使用初始化列表是C中推荐的初始化类成员变量的方式因为它提供了更好的性能和灵活性。 2.7.4 this关键字 在 C 中 this 关键字是一个指向调用对象的指针。它在成员函数内部使用用于引用调用该函数的对象。使用 this 可以明确指出成员函数正在操作的是哪个对象的数据成员。 示例代码 下面的代码展示了如何使用 this 关键字 输出 在这个例子中 Car 类的构造函数使用 this 指针来区分成员变量和构造函数参数。同样 setYear 成员函数使用 this 指针来返回调用该函数的对象的引用这允许链式调用如 myCar.setYear(2021).display(); 。在 main 函数中创建了 Car 类型的对象并展示了如何使用这 些成员函数。 2.7.5 new关键字 在C中 new 关键字用于动态分配内存。它是C中处理动态内存分配的主要工具之一允许在程序运行时根据需要分配内存。 基本用法 分配单个对象使用 new 可以在堆上动态分配一个对象。例如 new int 会分配一个 int 类型的空 间并返回一个指向该空间的指针。 int* ptr new int; //C语言中int *p (int *)malloc(sizeof(int)); 分配对象数组 new 也可以用来分配一个对象数组。例如 new int[10] 会分配一个包含10个整数的数组。 int* arr new int [ 10 ]; //C 语言中 int *arr (int *)malloc(sizeof(int)*10); 初始化可以在 new 表达式中使用初始化。对于单个对象可以使用构造函数的参数 MyClass * obj new MyClass ( arg1 , arg2 ); 与 delete 配对使用 使用 new 分配的内存必须显式地通过 delete 对于单个对象或 delete[] 对于数组来释放以避免内存泄露 释放单个对象 delete ptr; // 释放 ptr 指向的对象 释放数组 delete[] arr; // 释放 arr 指向的数组 注意事项 异常安全如果 new 分配内存失败它会抛出 std::bad_alloc 异常。 内存泄露忘记释放使用 new 分配的内存会导致内存泄露。 匹配使用 delete 和 delete[ ] 为避免未定义行为使用 new 分配的单个对象应该使用 delete 释放使用 new[ ] 分配的数组应该使用 delete[ ] 释放。 示例代码 class MyClass { public :         MyClass ()         {                 std::cout Object created std::endl ;         } }; int main () {         // 分配单个对象         MyClass * myObject new MyClass ();         // 分配对象数组         int* myArray new int [ 5 ]{ 1 , 2 , 3 , 4 , 5 };         // 使用对象和数组 ...         // 释放内存         delete myObject ;         delete [ ] myArray ;         return 0 ; } 在这个例子中 new 被用来分配一个 MyClass 类型的对象和一个整数数组然后使用 delete 和 delete[] 来释放内存。每个 new 都对应一个 delete 保证了动态分配的内存被适当管理。 2.8 析构函数 2.8.1 什么是析构函数 析构函数是C中的一个特殊的成员函数它在对象生命周期结束时被自动调用用于执行对象销毁前的清理工作。析构函数特别重要尤其是在涉及动态分配的资源如内存、文件句柄、网络连接等的情况下。 基本特性 1. 名称析构函数的名称由波浪号 ~ 后跟类名构成如 ~MyClass() 。 2. 无返回值和参数析构函数不接受任何参数也不返回任何值。 3. 自动调用当对象的生命周期结束时例如一个局部对象的作用域结束或者使用 delete 删除一个动态分配的对象析构函数会被自动调用。 4. 不可重载每个类只能有一个析构函数。 5. 继承和多态如果一个类是多态基类其析构函数应该是虚的。 示例 假设我们有一个类 MyClass 它包含了动态分配的内存或其他资源 输出 在这个示例中 MyClass 的构造函数分配了一块内存而析构函数释放了这块内存。当 obj 的生命周期结束时即离开了它的作用域 MyClass 的析构函数被自动调用负责清理资源防止内存泄露。 重要性 析构函数在管理资源方面非常重要。没有正确实现析构函数可能导致资源泄露或其他问题。在基于RAII资源获取即初始化原则的C编程实践中确保资源在对象析构时被适当释放是非常关键的。当使用智能指针和其他自动资源管理技术时可以减少显式编写析构函数的需要但了解析构函数的工作原理仍然很重要。 以下是关于 C 中析构函数需要了解的十个要点的表格 2.9 静态成员 2.9.1 静态成员的定义 静态成员在C类中是一个重要的概念它包括静态成员变量和静态成员函数。静态成员的特点和存在的 意义如下 静态成员变量 1. 定义静态成员变量是类的所有对象共享的变量。与普通成员变量相比无论创建了多少个类的实例静态成员变量只有一份拷贝。 2. 初始化静态成员变量需要在类外进行初始化通常在类的实现文件中。 3. 访问静态成员变量可以通过类名直接访问不需要创建类的对象。也可以通过类的对象访问。 4. 用途常用于存储类级别的信息例如计数类的实例数量或全局数据需要被类的所有实例共 享。 静态成员函数 1. 定义静态成员函数是可以不依赖于类的实例而被调用的函数。它不能访问类的非静态成员变量和非静态成员函数。 2. 访问类似于静态成员变量静态成员函数可以通过类名直接调用也可以通过类的实例调用。 3. 用途常用于实现与具体对象无关的功能或访问静态成员变量。 示例代码 存在的意义 共享数据允许对象之间共享数据而不需要每个对象都有一份拷贝。 节省内存对于频繁使用的类使用静态成员可以节省内存。 独立于对象的功能静态成员函数提供了一种在不创建对象的情况下执行操作的方法这对于实现 工具函数或管理类级别状态很有用。 2.9.2 静态成员变量的作用 静态成员变量在C中的一个典型应用是用于跟踪类的实例数量。这个案例体现了静态成员变量的特性 它们在类的所有实例之间共享因此适合于存储所有实例共有的信息。 下面是一个示例展示了如何使用静态成员变量来计数一个类的实例数量 在这个例子中 Myclass 类有一个静态成员变量 staticNumofInstance 用来跟踪该类的实例数量。 每当创建 Myclass 的新实例时构造函数会增加 staticNumofInstance 。 每当一个 Myclass 实例被销毁时析构函数会减少 staticNumofInstance 。 通过静态成员函数 getNunofInstance 可以随时获取当前的实例数量。 静态成员变量 staticNumofInstance 在类外初始化为0。 这个案例展示了静态成员变量如何在类的所有实例之间共享并为所有实例提供了一个共同的状态在这个例子中是实例的数量。这种技术在需要跟踪对象数量或实现某种形式的资源管理时特别有用。  2.10 继承 2.10.1 继承基本概念 继承是面向对象编程OOP中的一个核心概念特别是在C中。它允许一个类称为派生类或子类继承另一个类称为基类或父类的属性和方法。继承的主要目的是实现代码重用以及建立一种类型之间的层次关系。 特点 1. 代码重用子类继承了父类的属性和方法减少了代码的重复编写。 2. 扩展性子类可以扩展父类的功能添加新的属性和方法或者重写覆盖现有的方法。 3. 多态性通过继承和虚函数C支持多态允许在运行时决定调用哪个函数。 基本用法 在C中继承可以是公有public、保护protected或私有private的这决定了基类成员在派生类中的访问权限。 输出 在这个例子中 Bickle 类和Roadster类公有地继承自 Vehicle 类这意味着所有 Vehicle 类的公有成员在Bickle 类和Roadster类中也是公有的。 2.10.2 权限对继承的影响 在C中访问控制符对继承的影响可以通过下表来清晰地展示。这个表格展示了不同类型的继承 public 、 protected 、 private 如何影响基类的不同类型成员 public 、 protected 、 private 在派生类中的访问级别。 解释 public 继承基类的 public 成员在派生类中仍然是 public 的 protected 成员仍然是 protected 的。基类的 private 成员在派生类中不可访问。 protected 继承基类的 public 和 protected 成员在派生类中都变成 protected 的。基类 的 private 成员在派生类中不可访问。 private 继承基类的 public 和 protected 成员在派生类中都变成 private 的。基类的 private 成员在派生类中不可访问。 这个表格提供了一个快速参考帮助理解在不同类型的继承中基类成员的访问级别是如何变化的。记住无论继承类型如何基类的 private 成员始终不可直接在派生类中访问。 2.10.3 基类构造函数 在C中派生类可以通过其构造函数的初始化列表来调用基类的构造函数。这是在构造派生类对象时初始化基类部分的标准做法。 当创建派生类的对象时基类的构造函数总是在派生类的构造函数之前被调用。如果没有明确指定将调用基类的默认构造函数。如果基类没有默认构造函数或者你需要调用一个特定的基类构造函数就需要在派生类构造函数的初始化列表中明确指定。 输出 2.10.4 虚函数 在C中 virtual 和 override 关键字用于支持多态尤其是在涉及类继承和方法重写的情况下。正确地理解和使用这两个关键字对于编写可维护和易于理解的面向对象代码至关重要。 virtual 关键字 1. 使用场景在基类中声明虚函数。 2. 目的允许派生类重写该函数实现多态。 3. 行为当通过基类的指针或引用调用一个虚函数时调用的是对象实际类型的函数版本。 override 关键字 1. 使用场景在派生类中重写虚函数。 2. 目的明确指示函数意图重写基类的虚函数。 3. 行为确保派生类的函数确实重写了基类中的一个虚函数。如果没有匹配的虚函数编译器会报 错。 输出自行车跑起来 注意点 只在派生类中使用 override override 应仅用于派生类中重写基类的虚函数。 虚析构函数如果类中有虚函数通常应该将析构函数也声明为虚的。 默认情况下成员函数不是虚的在C中成员函数默认不是虚函数。只有显式地使用 virtual 关键字才会成为虚函数。 继承中的虚函数一旦在基类中声明为虚函数该函数在所有派生类中自动成为虚函数无论是否 使用 virtual 关键字。 正确使用 virtual 和 override 关键字有助于清晰地表达程序员的意图并利用编译器检查来避免常 见的错误如签名不匹配导致的非预期的函数重写。 2.10.5 多重继承 在C中多重继承是一种允许一个类同时继承多个基类的特性。这意味着派生类可以继承多个基类的属性和方法。多重继承增加了语言的灵活性但同时也引入了额外的复杂性特别是当多个基类具有相同的成员时。 基本概念 在多重继承中派生类继承了所有基类的特性。这包括成员变量和成员函数。如果不同的基类有相同名称的成员则必须明确指出所引用的是哪个基类的成员。 示例 假设有两个基类 ClassA 和 ClassB 以及一个同时从这两个类继承的派生类 Derived class ClassA { public:         void displayA()         {                 std::cout Displaying ClassA std::endl;         } }; class ClassB { public:         void displayB()         {                 std::cout Displaying ClassB std::endl;         } }; class Derived : public ClassA, public ClassB { public:         void display()         {                 displayA(); // 调用 ClassA 的 displayA                 displayB(); // 调用 ClassB 的 displayB         } }; int main() {         Derived obj;         obj.displayA(); // 调用 ClassA 的 displayA         obj.displayB(); // 调用 ClassB 的 displayB         obj.display(); // 调用 Derived 的 display         return 0; } 在这个示例中 Derived 类同时继承了 ClassA 和 ClassB 。因此它可以使用这两个类中定义的方法。 在这个实例中如果不同的基类有相同名称的成员则必须明确指出所引用的是哪个基类的成员。 注意事项 菱形继承问题如果两个基类继承自同一个更高层的基类这可能导致派生类中存在两份基类的副 本称为菱形继承或钻石继承问题。这可以通过虚继承来解决。 复杂性多重继承可能会使类的结构变得复杂尤其是当继承层次较深或类中有多个基类时。 设计考虑虽然多重继承提供了很大的灵活性但过度使用可能导致代码难以理解和维护。在一些 情况下使用组合或接口纯虚类可能是更好的设计选择。 多重继承是C的一个强大特性但应谨慎使用。合理地应用多重继承可以使代码更加灵活和强大但不当的使用可能导致设计上的问题和维护困难。 2.10.6 虚继承 虚继承是C中一种特殊的继承方式主要用来解决多重继承中的菱形继承问题。在菱形继承结构中一个类继承自两个具有共同基类的类时会导致共同基类的成员在派生类中存在两份拷贝这不仅会导致资源浪费还可能引起数据不一致的问题。虚继承通过确保共同基类的单一实例存在于继承层次中来解决这一问题。 菱形继承问题示例 考虑以下的类结构 class Base { public:         int data; }; class Derived1 : public Base {         // 继承自 Base }; class Derived2 : public Base {         // 继承自 Base }; class FinalDerived : public Derived1, public Derived2 {         // 继承自 Derived1 和 Derived2 }; 在这个例子中 FinalDerived 类通过 Derived1 和 Derived2 间接地继承自 Base 类两次。因此 它包含了两份 Base 的成员拷贝。 使用虚继承解决菱形继承问题 要解决这个问题应使用虚继承 class Base { public:         int data; }; class Derived1 : virtual public Base {         // 虚继承 Base }; class Derived2 : virtual public Base {         // 虚继承 Base }; class FinalDerived : public Derived1, public Derived2 {         // 继承自 Derived1 和 Derived2 }; 通过将 Derived1 和 Derived2 对 Base 的继承声明为虚继承 virtual public Base FinalDerived 类中只会有一份 Base 类的成员。无论通过 Derived1 还是 Derived2 的路径访问 的都是同一个 Base 类的成员。 特点和注意事项 初始化虚基类在使用虚继承时虚基类如上例中的 Base 类只能由最派生的类如 FinalDerived 初始化。 内存布局虚继承可能会改变类的内存布局通常会增加额外的开销比如虚基类指针。 设计考虑虚继承应谨慎使用因为它增加了复杂性。在实际应用中如果可以通过其他设计如 组合或接口避免菱形继承那通常是更好的选择。 虚继承是C语言中处理复杂继承关系的一种重要机制但它也带来了一定的复杂性和性能考虑。正确地使用虚继承可以帮助你建立清晰、有效的类层次结构。 2.11 多态 多态的基本概念(polymorphic) 想象一下你有一个遥控器这就像是一个基类的指针这个遥控器可以控制不同的电子设备这些设备就像是派生类。无论是电视、音响还是灯光遥控器上的“开/关”按钮这个按钮就像是一个虚函数都能控制它们但具体的操作打开电视、播放音乐、开灯则取决于你指向的设备。 2.11.1 如何实现多态 1. 使用虚函数Virtual Function 我们在基类中定义一个虚函数这个函数可以在任何派生类中被“重写”或者说“定制”。 使用关键字 virtual 来声明。 2. 创建派生类并重写虚函数 在派生类中我们提供该虚函数的具体实现。这就像是告诉遥控器“当你控制我的这个设备 时这个按钮应该这样工作”。 3. 通过基类的引用或指针调用虚函数 当我们使用基类类型的指针或引用来调用虚函数时实际调用的是对象的实际类型派生类 中的函数版本。 在这个例子中不同的对象 TvRemoteCon 和 TvRemoteCon 以它们自己的方式“开”尽管调用的是相同的函数 openUtils 。这就是多态的魅力——相同的接口不同的行为。 为什么使用多态 灵活性允许我们编写可以处理不确定类型的对象的代码。 可扩展性我们可以添加新的派生类而不必修改使用基类引用或指针的代码。 接口与实现分离我们可以设计一个稳定的接口而将具体的实现留给派生类去处理。 2.11.2 抽象类 抽象类的基本概念 想象一下你有一个“交通工具”的概念。这个概念告诉你所有交通工具都应该能做什么比如移动 move但它并不具体说明怎么移动。对于不同的交通工具比如汽车和自行车它们的移动方式是不同的。在这个意义上“交通工具”是一个抽象的概念因为它本身并不能直接被使用。你需要一个具体的交通工具比如“汽车”或“自行车”它们根据“交通工具”的概念具体实现了移动的功能。 在 C 中抽象类就像是这样的一个抽象概念。它定义了一组方法比如移动但这些方法可能没有具体的实现。这意味着抽象类定义了派生类应该具有的功能但不完全实现这些功能。 抽象类的特点 1. 包含至少一个纯虚函数 抽象类至少有一个纯虚函数。这是一种特殊的虚函数在抽象类中没有具体实现而是留给派 生类去实现。 纯虚函数的声明方式是在函数声明的末尾加上 0 。 2. 不能直接实例化 由于抽象类不完整所以不能直接创建它的对象。就像你不能直接使用“交通工具”的概念去任 何地方你需要一个具体的交通工具。 3. 用于提供基础结构 抽象类的主要目的是为派生类提供一个共同的基础结构确保所有派生类都有一致的接口和行 为。 #include iostream using namespace std; class Teacher { public:         string name;         string shool;         string major;         virtual void goInClass() 0;         virtual void startTeaching() 0;         virtual void afterTeaching() 0; }; class EnglishTeacher : public Teacher { public:         void goInClass() override         {                 cout 英语老师开始进入教室 endl;         }         void startTeaching() override         {                 cout 英语老师开始教学 endl;         }         void afterTeaching() override         {         }; }; class ProTeacher : public Teacher { public:         void goInClass() override         {                 cout 编程老师开始进入教室 endl;         }         void startTeaching() override         {                 cout 编程老师开始撸代码了拒绝读PPT endl;         }         void afterTeaching() override         {                 cout 编程老师下课后手把手教x学员写代码 endl;         }; }; int main() {         // Teacher t;//抽象类不支持被实例化         EnglishTeacher e;         e.goInClass();         ProTeacher t;         t.startTeaching();         t.afterTeaching();         //抽象类多态         Teacher *teacher new ProTeacher;         teacher-startTeaching();         return 0; } 2.12 模版 在 C 中模板Template是一种通用的编程工具允许程序员编写泛型代码使得类或函数能够适用于多种不同的数据类型而不需要重复编写相似的代码。C 提供了两种主要类型的模板类模板和函数模板。 类模板Class Templates 类模板允许定义通用的类其中某些类型可以作为参数。这样的类可以处理不同类型的数据而不需要为每个数据类型编写单独的类。 #include iostreamusing namespace std;class PrintInt { private:int data; public:void printInt(){cout data endl;}void setInt(int data){this-data data;} };class PrintString { private:string data; public:void printString(){cout data endl;}void setString(string data){this-data data;} };templatetypename T class PrintT { private:T data; public:void printT(){cout data endl;}void setT(T data){this-data data;} };int main() {PrintInt p1;p1.setInt(10);p1.printInt();PrintString p2;p2.setString(chenzhuo);p2.printString();PrintTint p3;p3.setT(10);p3.printT();PrintTstring p4;p4.setT(dashuaige);p4.printT();return 0; }输出
http://www.w-s-a.com/news/274655/

相关文章:

  • 网站开发 瀑布结构普陀网站建设
  • 12380网站建设情况汇报plone vs wordpress
  • c 网站开发数据库连接与wordpress类似的都有哪些
  • 状元村建设官方网站长春做网站seo的
  • 做金融资讯网站需要哪些牌照海珠营销型网站制作
  • 学做网站需要买什么书手机网络
  • 寻找做电影网站团队合作西宁网站建设君博首选
  • 兴仁县城乡建设局网站爱站关键词查询
  • 漳州网站建设公司推荐wordpress更改主机
  • c2c商城网站建设方案英文网站注册
  • 电子商务网站的运营一般需要做哪些准备宣传片拍摄思路
  • 网站建设网页制作百度怎么做自己网站
  • 建设设计网站公司巴州建设局网站
  • 淘宝建设网站的好处韶关市网站建设招标
  • 佛山高端网站免费招聘网站建设
  • 申请网站就是做网站吗wordpress tag 优化
  • 建站系统排行榜菏泽机关建设网站
  • 网站群建设费用科技通信网站模板下载
  • 网站开发的流程是怎样的自己做自媒体在哪个网站比较好
  • 网站的html代码在哪网页线上开发制作
  • 免费商用自媒体图片网站做网站好的公司有哪些
  • 阿雷网站建设公司中国建筑考试网官网首页
  • 厦门网站制作网页无法跳转到建设银行网站
  • 怎么建设自己网站简述网页布局的几种方法
  • 软文营销文案100篇如何优化搜索引擎的搜索功能
  • 做网站创意杭州家具网站建设方案
  • 福州seo网站推广优化乐清建网站
  • 莆田cms建站模板简述网站设计流程
  • 班级网站建设组织机构建设注册中心网站首页
  • 即墨网站建设地址怎么在文档中做网站一点就开