类与对象(5)
上一章是类与对象(4)-CSDN博客 深入了构造函数和静态成员,大概讲解了类型转换
最后一章最后一章
友元
在 C++ 中,友元提供了一种突破类的访问控制(封装)的方式。通过友元,外部的函数或类可以访问类的私有成员和保护成员。友元分为友元函数和友元类。在类声明中使用 friend
关键字来声明友元。
友元函数
-
定义:友元函数并不是类的成员函数,但它可以访问类的私有和保护成员。友元函数是在类的外部定义的独立函数,通过
friend
声明,告诉编译器这个函数可以访问类的私有成员。 -
声明位置:友元函数的声明位置可以在类定义中的任何地方。它不受类的访问权限(如
private
、protected
、public
)的限制,可以在类定义中的任意位置声明。 - 作用:友元函数的主要作用是允许外部函数访问类的私有成员,从而为一些特殊的需求提供便利。由于它不是类的成员函数,所以它不属于类的一部分,但是它拥有对类私有成员的访问权限。
class Box {
private:int length;
public:Box() : length(0) {}// 友元函数声明friend void setLength(Box& b, int len);
};// 友元函数定义
void setLength(Box& b, int len) {b.length = len; // 可以访问 Box 类的私有成员
}
- 多重友元:一个函数可以是多个类的友元函数。例如,
func1
可以是ClassA
和ClassB
的友元函数,可以同时访问这两个类的私有成员。
class ClassA;
class ClassB;void func1(ClassA& a, ClassB& b); // 友元函数可以访问多个类的私有成员
友元类
-
定义:友元类是一个类,它可以访问另一个类的私有和保护成员。当一个类是另一个类的友元类时,友元类的所有成员函数都有权访问被友元类的私有成员。友元类的关系也是单向的,即如果
ClassA
是ClassB
的友元类,那么ClassB
并不是ClassA
的友元类。 -
关系:友元类的成员函数可以访问另一个类的私有成员,意味着友元类可以通过它的成员函数来操作其他类的私有数据。即使
ClassA
和ClassB
中有相同的私有成员,友元类的成员函数仍然可以直接访问。
class ClassB;class ClassA {
private:int dataA;
public:ClassA() : dataA(0) {}// 将 ClassB 作为友元类friend class ClassB;
};class ClassB {
public:void modify(ClassA& a) {a.dataA = 10; // 可以访问 ClassA 的私有成员}
};
友元关系的特点
-
单向性:友元关系是单向的。比如,
ClassA
是ClassB
的友元类,但这并不意味着ClassB
也是ClassA
的友元类。要实现双向友元关系,必须显式地将另一个类声明为友元。 -
不可传递性:友元关系是不可传递的。即使
ClassA
是ClassB
的友元,ClassB
又是ClassC
的友元,这并不意味着ClassA
是ClassC
的友元。友元关系不能像继承一样传递。 -
友元函数和友元类的访问权限:友元函数和友元类的成员函数可以访问类的私有成员和保护成员。虽然它们不是类的成员,但它们被授权访问类内部的实现细节。
-
增加耦合度:友元关系虽然可以提供便利,但也会使得类之间的耦合度增加。特别是当多个类间相互成为友元时,会破坏类的封装性,因为这会使得类的内部实现细节暴露给外部的类或函数。
因此,尽量避免滥用友元,应该仅在确实需要的情况下才使用它。友元函数和友元类往往用于某些特定的场景,比如操作符重载、类之间的协作等。
为什么使用友元
-
访问权限的突破:友元最主要的功能就是突破类的访问权限控制,使得其他函数或类可以访问类的私有成员。这在某些特殊情况下非常有用,尤其是当你需要在类外部操作类的私有数据时。
-
实现操作符重载:在 C++ 中,很多操作符重载(如
<<
和>>
输入输出流操作符)通常需要将类定义为友元,以便能够访问类的私有成员。
友元的使用建议
尽管友元为我们提供了方便的功能,但它也会增加类之间的耦合度,破坏封装性。因此,友元函数和友元类的使用要谨慎,避免过度依赖友元。如果可能,尽量通过类的公有接口来访问类的私有数据,而不是使用友元。
内部类
内部类是在一个类的内部定义的类,它和普通类相比主要有一些特殊的作用域和访问权限规则。通过将一个类定义在另一个类的内部,可以增加封装性,使得类与类之间的关系更加紧密。以下是对内部类的详细讲解:
定义和特点
-
独立性:内部类本质上是一个独立的类,它有自己的作用域和生命周期。它不像外部类那样受到全局作用域的限制,而是仅限于外部类的作用域内。
尽管它被定义在外部类的内部,内部类依然是一个完整的类,与外部类没有直接的继承或包含关系。例如,外部类
A
内部定义的类B
,B
仍然是一个独立的类。 -
访问限定符限制:内部类受外部类的访问限定符(
private
、protected
、public
)的影响。如果外部类是private
,那么内部类也会受到同样的限制;如果外部类是public
,那么内部类的访问限制会根据其自身的声明来决定。 -
外部类不包含内部类:外部类的对象中并不会包含内部类对象,除非明确实例化内部类的对象。内部类是外部类的一个成员,但外部类并没有包含内部类作为其成员变量的一部分。
内部类的访问权限
-
默认友元类:内部类默认是外部类的友元类,这意味着内部类可以访问外部类的所有私有成员和保护成员。反过来,外部类无法直接访问内部类的私有成员,除非通过公开的接口。
例如:
class Outer { private:int x; public:Outer() : x(10) {}class Inner {public:void accessOuter(Outer& o) {// 内部类访问外部类的私有成员cout << "Accessing Outer's private member x: " << o.x << endl;}}; };int main() {Outer::Inner inner;Outer outer;inner.accessOuter(outer); // 访问外部类的私有成员return 0; }
-
作用域控制:内部类只能在外部类的作用域中被访问,这使得它只能在外部类中使用,增强了封装性。其他类无法直接访问或创建外部类内部的类。
设计上的优势
-
封装性:内部类常用于增强封装。当两个类之间有非常紧密的关系时,把一个类设计为另一个类的内部类是非常合适的。这种设计可以把一个类完全限制在另一个类的作用域中,只在必要的时候才提供外部访问。
-
专属类设计:如果你有一个类,它只会被另一个类使用,且不需要外部其他地方访问时,可以将其作为内部类进行设计。例如,
B
类仅为A
类提供某些服务,那么就可以把B
类设计成A
类的内部类,而不暴露给外部。 -
类之间的紧密联系:内部类的设计使得两个类之间的关系更加紧密。
A
类和B
类不再是松散的独立实体,它们有着更加明确的隶属关系。比如,你可以将B
类的成员限制为只在A
类的作用域内使用,避免了外部使用时的误操作。
内部类的常见用法
- 辅助类的设计:当一个类需要一个辅助类来完成一些特定任务,但这个辅助类并不需要被外部访问时,可以考虑将其设计为内部类。
class Outer {
public:class Helper {public:void helperFunction() {cout << "Helper Function!" << endl;}};
};int main() {Outer::Helper helper;helper.helperFunction(); // 只能通过外部类访问内部类return 0;
}
- 面向对象设计中的迭代器模式:内部类常常在容器类设计中使用,例如,设计一个迭代器类作为内部类,以便访问容器的私有数据。
class Container {
private:vector<int> data;
public:class Iterator {private:vector<int>::iterator it;public:Iterator(vector<int>::iterator iterator) : it(iterator) {}int operator*() { return *it; }Iterator& operator++() { ++it; return *this; }bool operator!=(const Iterator& other) { return it != other.it; }};Container() {data.push_back(1);data.push_back(2);data.push_back(3);}Iterator begin() { return Iterator(data.begin()); }Iterator end() { return Iterator(data.end()); }
};int main() {Container c;for (auto it = c.begin(); it != c.end(); ++it) {cout << *it << " "; // 通过迭代器访问容器数据}return 0;
}
内部类的注意点
-
与外部类紧密耦合:内部类和外部类之间有较强的耦合性。如果外部类发生变化,内部类也可能需要做相应的调整。因此,在设计时需要考虑这种耦合度是否符合预期的设计目标。
-
访问控制:尽管内部类可以访问外部类的私有成员,但外部类不能直接访问内部类的私有成员。如果你希望外部类也能访问内部类的成员,可以提供适当的公有接口。
-
内存管理:如果内部类和外部类的对象关系密切,需要特别注意内存管理问题,避免出现不必要的内存泄漏或引用问题。
匿名对象
在编程中,匿名对象是没有名字的临时对象。相比传统的有名字的对象(比如“类型 对象名(实参)”),匿名对象通过“类型(实参)”的方式被临时创建。这种方式极大地简化了代码,避免了不必要的命名,同时也能清晰地表达我们只关心对象的短期行为,而不需要后续访问它。
特点:
-
短生命周期:匿名对象的生命周期异常短暂,它们只存在于当前的代码行内。换句话说,它们就像是昙花一现,创建后立刻完成任务并销毁,不会占用额外的内存或资源。对于只需要执行一次特定任务的情况,匿名对象完美适用。
-
临时性与独立性:匿名对象没有名称,它们是孤立的,不会与程序中的其他部分发生联系。它们的作用通常仅限于创建它们的那一行代码,在这一行结束后,它们会立刻被销毁。这种“即生即死”的特性让它们非常适合于一次性的操作。
class Person {
public:Person(const std::string& name) {std::cout << "Creating Person: " << name << std::endl;}~Person() {std::cout << "Destroying Person." << std::endl;}
};int main() {// 使用匿名对象创建并立即执行操作Person("Alice");// 匿名对象在这一行结束后销毁return 0;
}
在上面的代码中,Person("Alice")
是一个匿名对象。它在这行代码执行时创建,完成打印操作后,它就会立即销毁。整个过程没有变量名,也不需要开发者去管理它的生命周期,C++ 会自动处理。
匿名对象的实际用途:
-
简洁高效:有时你只需要临时创建一个对象来完成某项任务,匿名对象能够简洁地实现这一点。例如,你可能只是需要创建一个对象传递给某个函数,而不需要在整个程序中反复使用它。这样就不需要定义多余的变量名,代码既简洁又清晰。
例如,我们常见的流操作中,经常用到匿名对象:
std::cout << "Hello, World!" << std::endl;
这里的
std::cout
和std::endl
都是匿名对象,创建后立即使用,之后会被销毁。
- 临时传参:当函数需要传递一个临时对象时,匿名对象尤其有用。例如,构造函数或方法可能需要接受一个临时对象作为参数,匿名对象正好可以完成这一任务,而无需为对象额外命名。
class Rectangle {
public:Rectangle(int width, int height) {std::cout << "Creating Rectangle with width " << width << " and height " << height << std::endl;}
};void printArea(const Rectangle& rect) {// 输出面积
}int main() {// 直接传递匿名对象printArea(Rectangle(5, 10));
}
这里,Rectangle(5, 10)
就是一个匿名对象,它仅仅为了传递给 printArea
方法而创建,之后立即销毁。
匿名对象的局限性:
-
生命周期有限:匿名对象的生命周期极为短暂,它们无法在代码的其他地方使用。一旦当前代码行执行完毕,匿名对象即刻销毁,内存被回收。因此,如果你想在其他地方访问该对象的数据或方法,显然匿名对象无法满足需求。
-
不可引用或修改:由于匿名对象没有名称,你无法像有名对象那样通过指针或引用来操作它们。如果你的代码需要反复操作一个对象,或者保持该对象的状态,使用匿名对象则不合适。
对象拷贝时的编译器优化
在现代 C++ 编译器中,优化对象拷贝的过程是提高程序性能的重要手段。尤其是在对象传递和返回时,拷贝操作可能是一个性能瓶颈。为了提高效率,编译器会尽量避免不必要的对象拷贝,尤其是在不影响程序正确性的情况下,进行一些“聪明”的优化。
编译器优化的基本原则:
编译器的目标是尽量减少不必要的拷贝操作,提高程序的执行效率。在某些情况下,拷贝操作可能是多余的,编译器会在编译阶段识别这些冗余的拷贝并尝试消除它们。这些优化主要集中在以下几个方面:
-
避免临时对象的拷贝:如果一个函数的参数是传值形式,并且传递给函数的实参是一个临时对象,编译器可能会识别到这个临时对象在函数结束后并不再使用,从而避免了不必要的拷贝。
-
合并拷贝:现代编译器会识别出在同一个表达式中连续发生的多个拷贝操作,并尝试将它们合并,减少拷贝的次数。这种优化会在表达式的计算过程中自动完成,而不需要程序员干预。
-
跨行跨表达式的优化:一些更“激进”的编译器会进行跨行或跨表达式的优化。即使是在不同代码行或表达式中发生的对象拷贝,编译器也可能会发现这些拷贝是冗余的,并将它们合并成一次有效的拷贝操作。
示例:合并拷贝的优化
class Person {
public:Person(const std::string& name) : name(name) {}std::string name;
};Person createPerson() {return Person("Alice");
}int main() {Person p1 = createPerson(); // 对象拷贝1Person p2 = p1; // 对象拷贝2return 0;
}
在这段代码中,我们有两个对象拷贝:
- 第一个拷贝发生在
createPerson()
函数返回时。这里返回了一个临时对象,通常会发生一次拷贝。 - 第二个拷贝发生在
p2 = p1
时,这又是一次拷贝。
在没有优化的情况下,编译器可能会执行两次拷贝。然而,现代编译器(例如 GCC、Clang、MSVC)会进行优化,合并这些拷贝。具体的优化方式可能包括:
- 使用 返回值优化(RVO) 或 命名返回值优化(NRVO) 来避免
createPerson()
函数中的临时对象拷贝。 - 对于
p2 = p1
,如果编译器发现p1
和p2
实际上是完全相同的对象(无副作用的赋值),它可能会直接将p1
的内容移动到p2
,从而避免拷贝。
进一步的优化:移动语义
随着 C++11 引入的移动语义,编译器在拷贝和赋值时可以进一步优化。例如,使用 std::move
或者编译器能够自动识别某些场景并将拷贝操作转换为移动操作,从而减少不必要的数据复制。
Person createPerson() {return Person("Alice"); // 返回临时对象
}int main() {Person p1 = createPerson(); // 返回值优化 (RVO),避免拷贝Person p2 = std::move(p1); // 移动构造函数,避免拷贝return 0;
}
在这种情况下,std::move(p1)
会将 p1
的资源“转交”给 p2
,而不需要拷贝数据,从而进一步提高性能。
编译器优化的实现
不同的编译器可能有不同的优化策略,编译器在拷贝操作时进行的优化可能有所不同。主流编译器如 GCC、Clang 和 MSVC 都有一定的优化能力,能够识别不必要的拷贝,并在可能的情况下进行合并和消除。然而,C++ 标准并没有明确规定编译器应该如何优化对象拷贝,因此不同编译器之间的实现可能会有所差异。
- GCC 和 Clang:这两个编译器非常注重性能,它们有能力通过 RVO、NRVO 和移动语义进行深度优化,甚至跨表达式、跨行合并拷贝。
- MSVC:微软的编译器也具备类似的优化能力,特别是在进行 STL 容器操作时,MSVC 的编译器在拷贝构造和赋值操作中有显著的优化。
结束!
相关文章:
类与对象(5)
上一章是类与对象(4)-CSDN博客 深入了构造函数和静态成员,大概讲解了类型转换 最后一章最后一章 友元 在 C 中,友元提供了一种突破类的访问控制(封装)的方式。通过友元,外部的函数或类可以访…...
AI知识架构之数据采集
数据采集 数据格式: 结构化数据:以固定格式和结构存储,如数据库中的表以及 Excel 表格,易于查询和分析。半结构化数据:有一定结构但不如结构化数据严格,XML 常用于数据交换,JSON 在 Web 应用中广泛用于数据传输和存储。非结构化数据:无预定义结构,文本、图像、音频和视…...

细说STM32F407单片机2个ADC使用DMA同步采集各自的1个输入通道的方法
目录 一、示例说明 二、工程配置 1、RCC、DEBUG、CodeGenerator 2、USART6 3、TIM3 (1)Mode (2)参数设置 (3) TRGO (4)ADC1_IN0 1)ADCs_Common_Settings 2&a…...
C# 将非托管Dll嵌入exe中(一种实现方法)
一、环境准备 电脑系统:Windows 10 专业版 20H2 IDE:Microsoft Visual Studio Professional 2022 (64 位) - Current 版本 17.11.4 其他: 二、测试目的 将基于C++创建DLL库,封装到C#生成的exe中。 一般C++创建的库,在C#中使用,都是采用DllImport导入的,且要求库处…...

完美解决:.vmx 配置文件是由 VMware 产品创建,但该产品与此版 VMware Workstation 不兼容
参考文章:该产品与此版 VMware Workstation 不兼容,因此无法使用 问题描述 当尝试使用 VMware Workstation 打开别人的虚拟机时,可能会遇到以下报错: 此问题常见于以下场景: 从其他 VMware 版本(如 ESX…...

使用大语言模型对接OA系统,实现会议室预定功能
随着人工智能技术的不断进步,越来越多的企业开始借助 AI 助手来提高工作效率,尤其是在日常事务的自动化处理中。比如,在许多公司里,会议室的预定是一个常见且频繁的需求,通常需要员工手动检查空闲时间并做出选择。而通…...

Ryu控制器:L2交换功能实现案例
基于 Ryu控制器 在 VM1--OVS--VM2 的简单拓扑中实现流量自动下发(流表动态安装)的完整案例。通过该案例,当VM1与VM2首次通信时,Ryu控制器会动态学习路径并下发流表,后续流量将直接由交换机转发,无需控制器介…...

动手学深度学习2025.2.23-预备知识之-线性代数
3.线性代数 (1)向量维数和张量维数的区别: (2)普通矩阵乘法: 要求左矩阵的列数等于右矩阵的行数 import torch # 创建两个矩阵 A torch.tensor([[1, 2], [3, 4]], dtypetorch.float32) B torch.tensor([[5, 6], [7, 8]], d…...

登录-07.JWT令牌-登录后下发令牌
一.思路 我们首先完成令牌生成。 在响应数据这一块 该响应数据是一个标准的Result结构,其中"data"的值就是一个JWT令牌。因此我们只需要将生成的JWT令牌封装在Result当中然后返回给前端即可。 备注是给前端看的,不用管。以后我们做校验时&…...

机器学习实战(7):聚类算法——发现数据中的隐藏模式
第7集:聚类算法——发现数据中的隐藏模式 在机器学习中,聚类(Clustering) 是一种无监督学习方法,用于发现数据中的隐藏模式或分组。与分类任务不同,聚类不需要标签,而是根据数据的相似性将其划…...

【数据序列化协议】Protocol Buffers
一、为什么需要序列化? 数据跨平台/语言交互: 不同编程语言(如 Java、Python、Go)的数据结构不兼容,序列化提供统一的数据表示。例如:Java 的 HashMap 和 Python 的 dict 需转换为通用格式(如 …...

基于 Python 的电影市场预测分析系统设计与实现(源码 + 文档)
大家好,今天要和大家聊的是一款基于 Python 的“电影市场预测分析”系统的设计与实现。项目源码以及部署相关事宜请联系我,文末附上联系方式。 项目简介 基于 Python 的“电影市场预测分析”系统主要面向以下用户角色:电影制片方、电影发行…...

计算机三级网络技术知识汇总【6】
第六章 交换机及其配置 1. 交换机基础 1.1 基本概念 局域网交换机是一种基于 MAC 地址识别,完成转发数据帧功能的一种网络连接设备。 工作在数据链路层,根据进入端口数据帧中的 MAC 地址进行数据帧的过滤、转发(也是交换机的工作原理&…...
2025教育与科研领域实战全解析:DeepSeek赋能细分场景深度指南(附全流程案例与资源)
🚀 2025教育与科研领域实战全解析:DeepSeek赋能细分场景深度指南(附全流程案例与资源)🚀 📚 目录 DeepSeek在教育与科研中的核心价值教学场景应用:从备课到课堂管理的全流程革新科研场景应用:从数据分析到论文写作的智能跃迁师生协同创新:AI赋能的个性化学习与科研…...
Linux 命令大全完整版(10)
4. 压缩与解压缩命令 gzip(gnu zip) 功能说明:压缩文件。语 法:gzip [-acdfhlLnNqrtvV][-S <压缩字尾字符串>][-<压缩效率>][–best/fast][文件…] 或 gzip [-acdfhlLnNqrtvV][-S <压缩字尾字符串>][-<压缩效率>][–best/f…...
彻底卸载kubeadm安装的k8s集群
目录 一、删除资源 二、停止k8s服务 三、重置集群 四、卸载k8s安装包 五、清理残留文件和目录 六、删除k8s相关镜像 七、重启服务器 一、删除资源 # 删除集群中的所有资源,包括 Pod、Deployment、Service,任意节点执行 kubectl delete --all pod…...

vue+element-plus简洁完美实现淘宝网站模板
目录 一、项目介绍 二、项目截图 1.项目结构图 2.首页 3.详情 4.购物车 5.登陆页 三、源码实现 1.路由配置 2.依赖包 四、总结 一、项目介绍 项目在线预览:点击访问 本项目为vue项目,参考淘宝官方样式为主题来设计元素,简洁美观&…...

学习aigc
DALLE2 论文 Hierarchical Text-Conditional Image Generation with CLIP Latents [2204.06125] Hierarchical Text-Conditional Image Generation with CLIP LatentsAbstract page for arXiv paper 2204.06125: Hierarchical Text-Conditional Image Generation with CLIP L…...
深度学习-127-LangGraph之基础知识(四)自定义状态添加额外字段的聊天机器人
文章目录 1 自定义状态2 自定义工具2.1 完善工具human_assistance2.2 浏览器工具baidu_search3 聊天机器人3.1 绑定工具的聊天模型3.2 聊天机器人(带记忆)4 调用图4.1 调用工具时中断4.2 人工提供信息恢复4.3 查询存储的状态4.4 手动更新状态5 参考附录使用LangGraph,在状态中…...
广东英语十二种应用文模版范文
1. 邀请信(Invitation Letter) 模版 Dear [Recipients Name],I hope this letter finds you well. I am writing to invite you to [Event Name] which will be held on [Date] at [Location]. The event will start at [Time] and we would be deligh…...

UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...

Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...