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

深度探索C++对象模型 学习笔记 第五章 构造、解构、拷贝语意学(1)

请看下面这个抽象基类的声明你能看出什么问题吗该类被设计成抽象基类纯虚函数的存在禁止创建 Abstract_base 的独立实例但它仍然需要一个显式的构造函数来初始化其唯一的数据成员 _mumble。如果没有这个初始化从 Abstract_base 派生的类其局部对象中的 _mumble 成员就处于未初始化状态。例如有人可能会说Abstract_base 的设计者本意是让每个派生类自己为 _mumble 提供初值。如果真是这样要想强制派生类这么做唯一的方法是提供一个带参数的 protected 构造函数一般而言类的数据成员应该只在该类的构造函数和其他成员函数内进行初始化和赋值。否则就会破坏封装让后续的维护和修改变得更加困难。另一种观点则认为设计错误并不在于缺少显式构造函数而在于抽象基类里声明了数据成员。这个论点更有说服力它涉及接口与实现的分离但并非放之四海皆准。把多个派生类共享的数据成员提升到基类中有时也是合理的设计选择。纯虚拟函数的存在Presence of a Pure Virtual Function刚接触 C 的程序员常常会惊讶地发现只要采用静态调用方式而非通过虚机制调用纯虚函数也可以被定义和调用。例如下面这段代码是合法的是否这么做通常由类设计者自行决定——但有一个例外。这个例外就是纯虚析构函数它必须由类设计者提供定义而不能将其定义为纯虚函数。为什么因为编译器会在每个派生类的析构函数内部隐式地加入对其所有虚基类和直接基类析构函数的静态调用。只要任何一个基类析构函数缺少定义就会导致链接错误。有人可能会问编译器在扩充派生类的析构函数的时候难道不应该主动抑制对纯虚析构函数的调用吗答案是不应该。因为类设计者可能确实为这个纯虚析构函数提供了定义就像前面的例子中定义了 Abstract_base::interface() 一样。整个设计本身就依赖于 C 语言的一个保证类对象继承体系中的每个析构函数都会被调用。所以编译器不能擅自省略这一调用。又有人会问如果类设计者忘记或不知道需要定义纯虚析构函数编译器难道不能自动合成它的定义吗答案依然是不能。由于可执行程序采用分离编译模型编译器无法自行判断。某些开发环境或许可以在链接时发现定义缺失并重新调用编译器带上合成定义的指令但据我所知目前没有任何实现能做到这一点。更好的设计选择是不要把虚析构函数声明为纯虚函数。虚拟规格的存在Presence of a Virtual Specification更应翻译为虚函数声明的问题Abstract_base::mumble() 不太适合作为虚函数因为它的算法与类型无关派生类几乎不可能改写它。更糟糕的是它的非虚实现是内联函数。如果频繁调用这个虚函数版本的实现性能损失会相当明显。不过有人可能会问编译器难道不能通过分析发现整个继承体系里只有一个实例存在吗如果确实如此它难道不能把虚调用转成静态调用进而允许内联展开吗问题是——如果后来给这个继承体系增加了新类而新类又引入了该函数的新实例呢这个新类会让之前的优化失效。此时该函数必须重新编译或者编译器生成第二个多态实例再通过流分析来决定实际该调用哪个实例。但问题在于该函数可能已经以二进制形式存在于某个库中。想要解开这种依赖关系很可能需要某种持久化的程序数据库或库管理器。总的来说把所有函数都声明成虚函数再指望编译器优化掉不必要的虚调用——这依然是一种糟糕的设计选择。虚拟规格中const的存在Presence of const within a Virtual Specification虚函数声明中的 const 限定判断一个虚函数是否应该为 const看起来好像很简单但实际在抽象基类里并不容易。这样做意味着要去预测数量可能无限的派生类实现会怎么使用这个函数。如果声明函数时不加 const那么这个函数就无法通过 const 引用或 const 指针来调用——至少不借助 const_cast 去掉常量性是做不到的。更麻烦的情况是先把函数声明成 const结果发现某个派生类的实例确实需要修改数据成员。我不知道业界有没有公认的解决办法但我可以证实这个问题的确存在。在我自己的代码里我倾向于不加 const。重新审视后的类声明前面的讨论表明下面这个 Abstract_base 的重声明似乎是更合适的设计5.1 “无继承”情况下的对象构造请看下面这个程序片段第 1、5、6 行代表了三种对象创建方式全局对象、局部对象和堆内存分配。第 7 行是一个类对象对另一个类对象的赋值操作第 10 行是用局部 Point 对象来初始化返回值。第 9 行显式删除了堆上分配的对象。对象的生命周期是运行时的一个属性。局部对象的生命周期从第 5 行定义开始到第 10 行结束。全局对象的生命周期贯穿整个程序运行。堆上分配的对象的生命周期则从 operator new 分配开始一直到调用 operator delete 为止。下面是用类似 C 的风格写出的第一版 Point 声明。标准称这种 Point 声明为 Plain Ol’ Data普通旧数据简称 POD在 C 下编译这个声明时会发生什么从概念上说编译器会为 Point 内部声明一个平凡的默认构造函数、平凡的析构函数、平凡的拷贝构造函数以及平凡的拷贝赋值运算符。不过在实际实现中编译器只是分析一下这个声明然后把它标记为 Plain Ol’ Data普通旧数据即 POD。当编译器遇到下面的定义时从概念上说Point 的平凡构造函数和析构函数都会被生成并调用构造函数在程序启动时调用析构函数通常在 main() 完成后由系统生成的 exit() 调用中执行。但在实际实现中这些平凡成员既不会被定义也不会被调用程序的行为和 C 语言下完全一样。嗯只有一个微小的区别。在 C 语言里global 被视为一个暂定性定义tentative definition因为它没有显式初始化。暂定性定义在程序里可以出现多次。链接编辑器会把这些多次出现的实例合并成一个然后把这一个实例放到程序数据段中专门存放未初始化全局对象的区域里由于历史原因这块区域叫 BSS是“Block Started by Symbol”的缩写源自 IBM 704 汇编器的一条伪指令。在 C 中暂定性定义不被支持因为类构造函数会隐式地应用进来诚然语言本可以对类对象和 Plain Ol’ Data 做出区分但这样做似乎引入了不必要的复杂化。因此在 C 中 global 被视为一个完整的定义这样就排除了第二个或后续定义的出现。所以 C 和 C 的一个区别在于BSS 数据段在 C 中的重要性相对降低——C 里的所有全局对象都被当作已初始化来处理。foobar() 函数第 5 行的局部 Point 对象同样既不会被构造也不会被析构。当然如果第一次使用比如第 7 行依赖于该局部对象有确定的值那么让它保持未初始化状态就可能成为一个程序缺陷。第 6 行的堆分配会被转化成一个对库函数 operator new 的调用同样operator new 返回的 Point 对象也不会应用默认构造函数。如果上一行的 local 已经被正确初始化那么再下一行的赋值可以解决这个问题但这个赋值语句很可能触发一条类似下面这样的编译器警告从概念上说这个赋值操作会触发平凡拷贝赋值运算符的定义并调用该运算符来执行赋值。不过在实际实现中因为对象是 Plain Ol’ Data所以赋值仍然只是逐位拷贝和在 C 语言中一样。第 9 行的 delete heap会被转换成对库函数 operator delete 的调用同样从概念上讲这会触发为 Point 生成平凡析构函数。但正如我们所见实际实现中这个析构函数既不会被生成也不会被调用。最后按值返回 local 从概念上会触发平凡拷贝构造函数的定义然后调用它依此类推。但在实际实现中这个返回操作仍然只是对 Plain Ol’ Data 的简单逐位拷贝。以上过程中global中的三个成员都会被零初始化因为静态存储期的对象C会在进入 main 之前先执行零初始化而local中的三个成员值会是随机值因为默认构造函数中没有为三个成员设置初始值即使是我们显式提供的构造函数如果没有为成员设置初始值成员的初始值也是随机的。抽象数据类型Abstract Data TypePoint 的第二版声明通过公共接口把私有数据完全封装了起来不过没有提供任何虚函数接口这样一个封装后的 Point 类对象大小没有变化仍然是三个连续排列的 float 坐标成员。私有关键字、公共关键字乃至成员函数的声明都不会在对象里占用任何空间。我们没有为 Point 类定义拷贝构造函数或拷贝运算符因为默认的逐位拷贝语义已经够用了。也没有提供析构函数——默认的程序内存管理方式足以胜任。定义一个全局实例现在默认构造函数会被应用到 global 上。由于 global 定义在全局作用域它的初始化需要推迟到程序启动时详见 6.1 节。有一种特殊情况把一个类初始化为全常量值。此时使用显式初始化列表比等价的构造函数内联展开要略微高效一些——即使是在局部作用域也是如此虽然在局部作用域这一点看起来有点反直觉。我们会在 5.4 节给出相关数据。例如看下面这段代码local1 的初始化比 local2 的初始化略微高效一些。这是因为初始化列表里的值可以在函数的活动记录activation record被压入程序堆栈时就直接放到 local1 的内存中。显式初始化列表有三个缺点1.只有当类的所有成员都是公有时才能使用为什么上例中三个坐标成员是私有也可以我自己测试也是可以的这是因为我自己测试时发现初始化列表实际调用的也是构造函数如果把构造函数去掉那么就只能在所有成员都是公有时才能使用显示初始化列表了。2.只能指定常量表达式那些能在编译期求值的表达式。3.由于编译器不会自动应用它对象未被初始化的风险大大增加。那么使用显式初始化列表带来的性能提升是否足以弥补它在软件工程上的这些缺陷呢通常来说不值得。但在某些特定场景下它确实能带来差别。例如你可能在手工构建某个大型数据结构比如调色板或者把大量常量值直接写到程序文本里比如某个复杂几何模型的控制顶点和节点值这类模型通常来自 Alias 或 SoftImage 等软件包。在这些情况下显式初始化列表的表现优于内联构造函数对于全局对象尤其明显。在编译器层面可以做这样一项优化识别出那些仅仅用常量表达式对成员逐一赋值的内联构造函数。编译器可以把这些常量值提取出来像对待显式初始化列表中的值一样去处理而不是把构造函数展开成一系列赋值语句。现在来看局部 Point 对象的定义此后默认的 Point 构造函数会被内联展开相当于第 6 行在堆上分配 Point 对象现在这里会包含一个对默认 Point 构造函数的有条件调用该构造函数随后会被内联展开。把局部对象赋值给 heap 所指向的对象这个赋值仍然只是简单的逐位拷贝。按值返回局部对象也是如此删除 heap 所指向的对象不会触发析构函数调用因为我们没有显式提供析构函数实例。从概念上说我们的 Point 类有一个相关联的默认拷贝构造函数、拷贝运算符和析构函数。不过它们都是平凡的编译器在实际中并不会生成它们。为继承做准备Point 的第三个版本开始为继承以及某些操作的动态决议做准备——这里仅限于访问坐标成员 z我们仍然没有定义拷贝构造函数、拷贝运算符或析构函数。所有成员都是按值存储的因此在默认语义下程序层面不会有问题有人可能会说一旦引入了虚函数就应该同时声明一个虚析构函数不过在这个例子里这样做毫无意义。引入虚函数后每个 Point 对象内部会多出一个虚表指针vptr。这给了我们虚接口的灵活性代价是每个对象多占用一个字word的存储空间。这个代价大不大显然取决于应用场景和领域。以 3D 建模为例如果你要表示一个复杂的几何形状其中有 60 个 NURBS 曲面每个曲面有 512 个控制顶点那么每个 Point 对象多出的 4 字节开销累积起来就接近 200,000 字节。这个开销是否值得需要与设计中多态带来的实际好处进行权衡。你所要避免的是等实现完成之后才意识到这个问题。除了在每个类对象中增加 vptr 之外引入虚函数还会导致编译器对 Point 类做如下扩充1.我们已经定义的构造函数会被插入初始化虚表指针的代码。这段代码必须在任何基类构造函数调用之后、用户提供的任何代码执行之前加入。例如下面是我们 Point 构造函数的一种可能的展开形式2.拷贝构造函数和拷贝运算符都需要被合成因为它们的操作不再是平凡的隐式析构函数仍然是平凡的因此不会被合成。如果用一个派生类对象来初始化或赋值给 Point 对象逐位操作可能会导致虚表指针被错误设置。作为优化编译器可能会把一个对象的连续内存块直接拷贝到另一个对象而不是严格实现逐成员赋值。C 标准要求实现编译器延迟这些非平凡成员的合成直到确实遇到它们的实际使用。为了方便起见我把 foobar() 的代码再次贴在这里第 1 行 global 的初始化、第 6 行 heap 的初始化以及第 9 行 heap 的删除与之前 Point 的第一版表示完全相同。不过第 7 行的逐成员赋值很可能会触发拷贝赋值运算符的实际合成并对该调用进行内联展开——用 heap 替换 this 指针用 local 替换右值参数 rhs。对我们的程序影响最大的是第 10 行按值返回 local 的操作。一旦有了拷贝构造函数foobar() 很可能被改写成下面这样2.3 节会详细讨论如果编译器支持具名返回值优化Named Return ValueNRV那么该函数会进一步改写如下一般来说如果你的设计中有大量函数需要按值定义并返回一个局部类对象例如下面这种形式的算术运算那么即使默认的逐成员语义已经够用提供一个显式的拷贝构造函数仍然非常合理。因为它的存在会触发 NRV 优化存疑可能是旧版编译器的特性新版可能已经优化。此外正如前一个例子所展示的这种优化一旦生效就不再需要真正调用拷贝构造函数——因为计算结果被直接放入了将要返回的那个对象中。5.2 继承体系下的对象构造当我们定义一个对象时比如究竟会发生什么如果 T 有关联的构造函数无论是用户提供的还是编译器合成的它就会被调用。这一点显而易见。但有时候不那么显而易见的是调用一个构造函数实际包含哪些操作构造函数可能隐含大量编译器自动插入的代码因为编译器会根据 T 的类继承体系的复杂程度对每个构造函数进行或多或少的扩充。编译器扩充的一般顺序如下1.成员初始化列表中的数据成员必须按照它们在类中声明的顺序放入构造函数的函数体里。2.如果某个成员类对象没有出现在成员初始化列表中但它有相关的默认构造函数那么该默认构造函数必须被调用。3.如果类对象中包含虚表指针可能不止一个则必须用相应虚表的地址来初始化这些指针。4.所有直接基类的构造函数必须按照基类声明的顺序被调用成员初始化列表中的顺序无关紧要。1如果基类出现在成员初始化列表中则必须传递其中给出的显式实参如果有。2如果基类没有出现在成员初始化列表中且该基类有默认构造函数或默认的逐成员拷贝构造函数则必须调用它。3如果该基类是第二个或更靠后的基类则必须调整 this 指针。5.所有虚基类的构造函数必须按照派生类继承体系所定义的、从左到右、深度优先的顺序被调用。1如果虚基类出现在成员初始化列表中则必须传递其中给出的显式实参如果有。否则如果该类有关联的默认构造函数则必须调用它。2此外每个虚基类子对象在类对象中的偏移量必须在运行时能以某种方式访问到。3不过这些构造函数仅当该类对象代表“最派生类”时才会被调用。为此必须引入某种机制来支持这一判断。在本节中我将探讨为了支持 C 语言所保证的类语义编译器需要在构造函数中做哪些扩充。我仍然用 Point 类来辅助说明为了展示后续的容器类和派生类在这些函数存在时的行为我特意增加了一个拷贝构造函数、一个拷贝赋值运算符和一个虚析构函数在深入探讨以 Point 为基类的继承体系之前我们先快速看一下 Line 类的声明及其扩充。Line 由一个起点和一个终点 Point 对象组合而成每个显式构造函数都会被扩充以调用其两个成员类对象的构造函数。例如下面这个用户定义的构造函数在内部会被扩充并改写成由于 Point 类声明了拷贝构造函数、拷贝赋值运算符和析构函数本例中为虚析构函数因此 Line 的隐式拷贝构造函数、拷贝赋值运算符和析构函数都变成了非平凡的。当程序员写下编译器会合成隐式的 Line 析构函数如果 Line 是从 Point 派生的那么合成的析构函数会是虚函数不过因为 Line 只是包含 Point 对象而非派生自 Point所以合成的 Line 析构函数是非虚的。在这个合成的析构函数中两个成员类对象的析构函数会按照与构造相反的顺序被调用当然如果 Point 的析构函数是内联的那么每次调用都会在调用点展开。请注意尽管 Point 的析构函数是虚函数但在容器类Line的析构函数中对其调用是以静态方式决议的。类似地当程序员写下编译器会合成隐式的 Line 拷贝构造函数作为一个内联公有成员。最近在查阅 cfront 的代码时我注意到它在生成拷贝赋值运算符时并不会加入下面这种自赋值保护的判断因此对于像下面这样的表达式它会执行冗余的拷贝操作。我发现这个问题并非 cfront 独有Borland 同样不加自赋值保护我推测大多数编译器都是如此。对于编译器合成的拷贝赋值运算符来说这种冗余拷贝是安全的——因为它不涉及资源的释放。不过在用户自己提供的拷贝赋值运算符中忘记检查自赋值是一个新手常犯的错误。例如说到“有心无力”的事情——我曾多次想在 cfront 中加入一条警告当拷贝赋值运算符里缺少自赋值保护同时又对某个成员执行了 delete 操作时就发出警告。我仍然认为这条警告对程序员会很有用。虚拟继承Virtual Inheritance请看下面从 Point 类进行的虚派生由于虚基类具有共享特性传统的构造函数扩充方式在这里行不通。例如下面这种扩充就是无效的你能看出上面这种对 Point3d 构造函数的扩充有什么问题吗考虑下面三个类的派生关系Vertex 的构造函数也必须调用 Point 类的构造函数。然而当 Point3d 和 Vertex 作为 Vertex3d 的子对象时它们对 Point 构造函数的调用不能发生相反由 Vertex3d 作为最派生类来负责初始化 Point。在后续的 PVertex 派生中则由 PVertex而不是 Vertex3d负责初始化那个共享的 Point 子对象。为了支持这种“有时你需要初始化虚基类有时你不需要”的机制传统的做法是在构造函数中增加一个额外的参数用来指示是否需要调用虚基类的构造函数。构造函数体内部会条件判断这个参数从而决定调用或不调用相关的虚基类构造函数。下面是对 Point3d 构造函数采用这种策略的扩充结果这种策略在语义上是正确的。例如当我们定义Point3d 的构造函​​数正确调用了其虚基类 Point 的子对象。当我们定义Vertex3d 的构造函数正确调用了 Point 的构造函数。而 Point3d 和 Vertex 的构造函数则执行了除该调用之外的所有操作。既然行为正确那问题出在哪里呢我们中的许多人都注意到虚基类构造函数在何时被调用其条件是明确定义的。当定义一个完整的类对象时例如 origin它们会被调用而当该对象作为后续派生类对象中的子对象时它们不会被调用。借助这一认识我们可以生成性能更好的构造函数——代价是生成更多的程序代码。一些较新的实现将每个构造函数拆分成两个版本完整对象版本和子对象版本1.完整对象版本无条件调用虚基类构造函数、设置所有虚表指针等。2.子对象版本不调用虚基类构造函数也可能不设置虚表指针等下一节会讨论虚表指针的设置问题。这种构造函数拆分应该能显著提升程序速度。遗憾的是我手头没有实际采用这种方案的编译器因此无法提供数据来证实这一点不过在 Foundation 项目期间Rob Murray——我猜他是出于无奈——手动优化了 cfront 生成的 C 代码消除了不必要的条件测试和虚表指针设置。他报告说取得了可测量的性能提升。

相关文章:

深度探索C++对象模型 学习笔记 第五章 构造、解构、拷贝语意学(1)

请看下面这个抽象基类的声明:你能看出什么问题吗?该类被设计成抽象基类(纯虚函数的存在禁止创建 Abstract_base 的独立实例),但它仍然需要一个显式的构造函数来初始化其唯一的数据成员 _mumble。如果没有这个初始化&am…...

JetBrains IDE试用期重置终极指南:轻松解决IDE过期问题

JetBrains IDE试用期重置终极指南:轻松解决IDE过期问题 【免费下载链接】ide-eval-resetter 项目地址: https://gitcode.com/gh_mirrors/id/ide-eval-resetter 你是否曾经遇到过这样的困扰:正在专注编码时,突然弹出的"试用期已结…...

Linux 进程从入门到实战(一)

.个人主页:晓风飞专栏:数据结构|Linux|C语言路漫漫其修远兮,吾将上下而求索文章目录进程为什么要存在内存??操作系统进程什么是进程?PCB(进程控制块)操作系统如何管理进程&#xff1…...

遥测数据定义的生产级落地规范指南

在分布式架构与微服务体系中,将 Tracing(链路)、Metrics(指标)、Logs(日志)三种遥测数据有机构建为“三位一体” (3D Observability) 的可观测性网络,是保障系统高可用性的基石。 以…...

Java智能地址解析终极指南:企业级架构设计与高性能实现方案

Java智能地址解析终极指南:企业级架构设计与高性能实现方案 【免费下载链接】address-parse Java 版智能解析收货地址 项目地址: https://gitcode.com/gh_mirrors/addr/address-parse 面对电商、物流、外卖等系统中复杂多变的地址输入格式,传统的…...

AMD Ryzen SMU Debug Tool完整指南:轻松掌握硬件级调试的5个关键步骤

AMD Ryzen SMU Debug Tool完整指南:轻松掌握硬件级调试的5个关键步骤 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地…...

【Linux】网络基础2---Socket编程预备

📌 相关专栏 【Linux专栏】【C语言专栏】【测试专栏】 上期回顾【Linux 】网络基础1 文章目录1. 理解源IP地址和目的IP地址2. 认识端口2.1端口号范围划分2.2 理解 "端⼝号" 和 "进程ID"2.3 源端口号与目的端口号2.4 理解Socket2. 传输层的典型代…...

Python初学者项目练习23--计算圆的面积

一、练习题目 定义一个函数,这个函数用于计算并返回给定半径的圆的面积(要求结果保留两位小数) 二、代码 1.初始版本 代码如下: def area(r):"""作用:用于计算并返回给定半径的圆的面积(要求…...

RAG:终结AI幻觉,让你的大语言模型秒变“知识渊博”!

本文深入浅出地介绍了检索增强生成(RAG)技术,解释了其如何通过结合文档检索与大语言模型(LLM),有效减少AI幻觉现象。文章详细阐述了RAG的工作流程,包括数据分块、嵌入转换、向量数据库存储、问题…...

Go 内存优化骚操作

1. 零内存占位符:struct{}{}原理:struct{} 是空结构体,Go 编译器对其做了特殊处理,它在内存中不占任何空间(大小为 0 字节)。场景 A:实现集合 (Set)map[string]struct{}。比起 map[string]bool&…...

凡亿AD22--AD软件泪滴的添加与移除

一、泪滴的基础认知1.1 泪滴的定义泪滴是PCB设计中,在走线与焊盘、走线与过孔(导孔)连接位置添加的「圆弧状或渐变状过渡结构」,本质是连接部位的“过渡加固层”,肉眼可见为类似水滴或圆弧的形态,核心作用是…...

2025_NIPS_Language Models Don‘t Always Say What They Think: Unfaithful Explanations in Chain-of-T...

文章主要内容与创新点总结 一、主要内容 该研究聚焦大语言模型(LLMs)的思维链(CoT)提示法,核心探讨CoT解释的“不忠实性”——即模型生成的分步推理过程可能无法真实反映其预测的底层逻辑,反而会系统性地误导用户。 研究背景:CoT提示法通过引导模型输出分步推理再给出…...

【项目实训(个人8)】

继续进行法律文书智能摘要系统的开发,新增了几个功能,并优化了用户体验概述本次开发为法律文书智能摘要系统新增了两项核心功能。其一是摘要版本管理,支持同一文档的多版本摘要生成、存储、对比和回滚。用户在生成摘要时,系统自动…...

运放电源端串联磁珠

在运放电源端串联磁珠,是一种常见的高频噪声抑制设计手段,但需结合具体应用场景谨慎使用。以下是关键要点:---作用与目的 - 抑制高频噪声:磁珠对高频信号(通常 >10 MHz)呈现高阻抗,将电源线上…...

Re: Linux系统篇(十八)进程篇·三:深度硬核!全面起底 Linux 进程状态变化与内核链表动态解绑

◆ 博主名称: 晓此方-CSDN博客 大家好,欢迎来到晓此方的博客。 ⭐️Linux系列个人专栏: 【主题曲】Linux ⭐️此方的GitHub: github_此方 ⭐️Re系列专栏:我们思考 (Rethink) 我们重建 (Rebuild) 我们记录 (Record…...

意识的“调谐客观还原”理论

“调谐客观还原”理论,通常称为 Orch-OR,是诺贝尔物理学奖得主罗杰彭罗斯与麻醉学家斯图尔特哈梅罗夫于20世纪90年代初提出的一种极具争议的意识假说。该理论的核心观点是:意识并非产生于神经元之间的经典电化学连接,而是源于神经…...

基于 Python 有限元法的光子微腔仿真:从理论到代码实现

引言:光子微腔与有限元法的结合实例# 安装基础依赖 pip install numpy matplotlib scipy# 安装GMSH网格生成器 pip install gmsh# 安装FEMWELL光子学有限元库 pip install femwell# 安装FEniCSx(FEMWELL的底层依赖) # 对于Ubuntu/Debian系统 …...

5分钟学会AnyFlip电子书一键下载:免费PDF转换终极指南

5分钟学会AnyFlip电子书一键下载:免费PDF转换终极指南 【免费下载链接】anyflip-downloader Download anyflip books as PDF 项目地址: https://gitcode.com/gh_mirrors/an/anyflip-downloader 你是否曾经在AnyFlip上找到一本精彩的电子书,想要永…...

多语言交易所源码/币币交易+期权交易+永续合约+Defi借贷+新币申购+矿机理财/前端uniapp纯源码+后端php

简介: 多语言交易所源码/币币交易期权交易永续合约Defi借贷新币申购矿机理财/前端uniapp纯源码后端php 语言:7种,看图 前端是uniapp纯源码,只有手机端,后端是php框架,清理了后门的,是最开始蓝…...

86、【Agent】【OpenCode】bash 工具提示词(完结)

【声明】本博客所有内容均为个人业余时间创作,所述技术案例均来自公开开源项目(如Github,Apache基金会),不涉及任何企业机密或未公开技术,如有侵权请联系删除 背景 上篇 blog 【Agent】【OpenCode】bash 工…...

根据等价类划分法,**有效等价类**是指符合系统规格说明、应被系统正常接受的输入范围

根据等价类划分法,有效等价类是指符合系统规格说明、应被系统正常接受的输入范围。 题目中密码长度要求为 6–12位(含端点),即最小长度为6,最大长度为12,且为整数位数。 因此,关于密码长度的有效…...

【软考高级架构】案例题考前突击——构建可观测与弹性服务架构的实践设计

案例分析题:构建可观测与弹性服务架构的实践设计 案例背景 某金融科技公司搭建了基于Spring Cloud 的微服务系统,用于支撑其多租户 SaaS 金融平台,核心功能包括用户管理、交易撮合、支付结算、风控审计等模块。由于业务快速扩张、团队并行开发,系统逐渐暴露出如下痛点: …...

Java全栈工程师面试实录:从基础到微服务的深度技术对话

Java全栈工程师面试实录:从基础到微服务的深度技术对话 面试官与程序员的对话 面试官(李哥): 你好,欢迎来参加我们公司的面试。我是李哥,负责技术面试。先简单介绍一下你自己吧。 程序员(张浩&a…...

【YOLOv8多模态融合改进】| IEEE2025 分层特征融合模块HFF 自适应权重 + 三重注意力,强化弱小目标细节保留

一、本文介绍 本文记录的是利用分层特征融合模块HFF改进YOLOv8的可见光-红外双模态目标检测。 HFF(Hierarchical Feature Fusion)通过浅层-深层特征逐元素融合、空间-通道-像素三重注意力建模与自适应加权分配结合,实现多模态来源下不同语义层级特征的自适应重要性学习与精…...

AI+HR 全生命周期智能管理实战指南:从概念到落地,解锁组织效能新增长!​

在企业数字化转型的浪潮中,人力资源管理正经历着前所未有的变革。据行业数据,61% 的 HR 领导者已进入 GenAI 实施进阶阶段,82% 的企业计划在 12 个月内部署 AI 智能体,而 AI 驱动的企业人均效能已实现3.2 倍提升。当传统 HR 深陷事…...

2026年AI面试准确率TOP榜:92%一致性背后,谁在定义行业新标准?

当年ChatGPT的横空出世,让全世界第一次见识到通用大模型的对话能力;DeepSeek 的爆发,则将AI的火种真正播撒到中国各行各业的毛细血管中,而在人力资源行业作为数字化转型的前沿阵地,首当其冲迎来了AI的全面渗透 &#x…...

如何优化鸿蒙 App 的启动速度?

子玥酱 (掘金 / 知乎 / CSDN / 简书 同名) 大家好,我是 子玥酱,一名长期深耕在一线的前端程序媛 👩‍💻。曾就职于多家知名互联网大厂,目前在某国企负责前端软件研发相关工作,主要聚…...

梳理尼日利亚外贸典型骗局分享高效避雷方法

与尼日利亚客户交易须防范D/P条款陷阱,信用证务必经第三国银行保兑,警惕提单信息泄露,掌握风控要点方能安全拓展西非市场。拒绝D/P托收条款切勿接受D/P付款方式。尼日利亚部分银行可能与客户勾结,在买方未付货款的情况下擅自放行提…...

ncmdumpGUI:免费解锁网易云音乐加密文件,3分钟实现跨设备播放自由

ncmdumpGUI:免费解锁网易云音乐加密文件,3分钟实现跨设备播放自由 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换,Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 你是否曾经遇到过这样…...

奇门对接顺丰电子面单:从200行“祖传代码”到优雅重构的经验分享

一、背景:那年写下的“能跑就行” 在我们的电商WMS系统中,发货环节需要通过菜鸟奇门电子面单接口向顺丰等快递公司申请运单号。这段核心代码写于多年前,当时的业务需求比较简单:只支持淘宝/天猫订单,快递也只有顺丰。…...