C++——入门基础(上)
目录
一、C++参考文档
二、C++在工作领域的应用
三、C++学习书籍
四、C++的第一个程序
五、命名空间
(1)namespace的定义
(2)命名空间的使用
六、C++的输入和输出
七、缺省函数
八、函数重载
九、写在最后
一、C++参考文档
(1)虽然不是C++官方文档且标准只更新到C++11,但是以头文件的形式呈现,内容易看好懂;
https://legacy.cplusplus.com/reference/
(2)C++官方文档的中文版和英文版,信息很全,更新到了最新的C++标准,但是相比第一个不是那么易看。
https://zh.cppreference.com/w/cpp
https://en.cppreference.com/w/
二、C++在工作领域的应用
(1)大型软件开发。如:编译器、数据库、操作系统、浏览器等。
(2)音视频处理。
(3)PC客户端开发。⼀般是开发Windows上的桌面软件,比如WPS之类的;技术栈的话一般是C++和 QT,QT是⼀个跨平台的C++图形用户界面(Graphical User Interface,GUI)程序。
(4)服务端开发。各种大型应⽤网络连接的高并发后台服务。这块Java也比较多,C++主要用于⼀些对性能要求比较高的地方。如:游戏服务、流媒体服务、量化高频交易服务等。
(5)游戏引擎开发。很多游戏引擎就都是使⽤C++开发的,游戏开发要掌握C++基础和数据结构,学习图形学知识,掌握游戏引擎和框架,了解引擎实现,引擎源代码可以学习UE4、Cocos2d-x等开源引擎实现。
(6)嵌入式开发。嵌入式把具有计算能力的主控板嵌入到机器装置或者电子装置的内部,通过软件能够控制这些装置。比如:智能手环、摄像头、扫地机器人、智能音响、门禁系统、车载系统等等,粗略⼀点,嵌入式开发主要分为嵌⼊式应⽤和嵌⼊式驱动开发。
(7)测试开发/测试。
(8)机器学习引擎。机器学习引擎。机器学习底层的很多算法都是用C++实现的,上层用python封装起来。如果你只想准备数据训练模型,那么学会Python基本上就够了,如果你想做机器学习系统的开发,那么需要学会C++。
三、C++学习书籍
(1)C++ Primer:主要讲解语法,经典的语法书籍,前后中期都可以看,前期如果自学看可能会有点晦涩难懂,中后期作为语法字典,非常好用。
(2)STL源码剖析:主要从底层实现的角度结合STL源码,庖丁解牛式剖析STL的实现,是侯捷老师的经典之作。可以很好的帮助我们学习别人用语法是如何实现出高效简洁的数据结构和算法代码,如何使用泛型封装等。
(3)Effctive C++:本书也是侯捷老师翻译的,本书有的⼀句评价,把C++程序员分为看过此书的和没看过此书的。本书主要讲了55个如何正确高效使用C++的条款。
四、C++的第一个程序
C++兼容C语言绝大多数的语法,所以C语言实现的hello world依旧可以运行:
#include <stdio.h>int main()
{printf("Hello world\n");return 0;
}
当然C++有⼀套自己的输入输出,C++中需要把定义文件代码后缀改为.cpp,vs编译器看到是.cpp就会调用C++编译器编译,linux下要用g++编译,不再是gcc。
严格说C++版本的hello world应该是这样写的:
#include <iostream>
using namespace std;int main()
{cout << "Hello world\n" << endl;return 0;
}
五、命名空间
(1)namespace的定义
①定义命名空间,需要用到namespace关键字,后面跟着命名空间的名字,然后用一对{}连接,{}中为命名空间的成员。命名空间可以定义变量/函数/类型等。
与结构体的区别是:{}后面没有分号;
namespace zfy
{//变量int rand = 10;//函数int Add(int a, int b){return a + b;}//类型struct Node{struct Node* next;int val;}
}
②namespace本质是定义出一个域,这个域跟全局域各自独立。
③不同的域可以定义同名变量,因此下面的两个rand不会冲突。
#include <stdio.h>
#include <stdlib.h>namespace zfy
{int rand = 10;int Add(int a, int b){return a + b;}struct Node{struct Node* next;int val;}
}int main()
{printf("%p\n",rand);//这里默认访问的是全局的rand函数指针(即头文件stdlib.h中的)printf("%d\n",zfy::rand);//这里访问的是命名空间中的randreturn 0;
}
④C++中域有函数局部域、全局域、命名空间域、类域;
域影响的是编译时语法查找⼀个变量/函数/ 类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。
局部域和全局域除了会影响编译查找逻辑,还会影响变量的生命周期,命名空间域和类域不影响变量生命周期。
//全局域
int rand = 10;//命名空间域
namespace zfy
{int rand = 10;int Add(int a, int b){return a + b;}struct Node{struct Node* next;int val;}
}//函数局部域
int Add(int a, int b)
{return a + b;
}int main()
{//函数局部域int rand = 10;return 0;
}
⑤namespace只能定义在全局(即不能在main函数或者其他函数中定义),当然他还可以嵌套定义。
//命名空间的嵌套
namespace zfy
{namespace z{int rand = 1;int Add(int left, int right){return left + right;}}namespace f{int rand = 2;int Add(int left, int right){return (left + right)*10;}}
}//调用
int main()
{printf("%d\n", zfy::z::rand);printf("%d\n", zfy::f::rand);printf("%d\n", zfy::z::Add(1, 2));printf("%d\n", zfy::f::Add(1, 2));return 0;
}
⑥项目工程中多文件中定义的同名namespace会认为是⼀个namespace,不会冲突。
// Stack.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>namespace zfy
{typedef int STDataType;typedef struct Stack{STDataType* a;int top;int capacity;}ST;void STInit(ST* ps, int n);void STDestroy(ST* ps);void STPush(ST* ps, STDataType x);void STPop(ST* ps);STDataType STTop(ST* ps);int STSize(ST* ps);bool STEmpty(ST* ps);
}// Stack.cpp
#include"Stack.h"
namespace zfy
{void STInit(ST* ps, int n){assert(ps);ps->a = (STDataType*)malloc(n * sizeof(STDataType));ps->top = 0;ps->capacity = n;}// 栈顶 void STPush(ST* ps, STDataType x){assert(ps);// 满了, 扩容 if (ps->top == ps->capacity){printf("扩容\n");int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));if (tmp == NULL){perror("realloc fail");return;}ps->a = tmp;ps->capacity = newcapacity;}ps->a[ps->top] = x;ps->top++;}}
比如说,我们在Stack.h和Stack.cpp中都定义了名为zfy的命名空间,但在使用时会被认为是一个命名空间,不会冲突:
// test.cpp
#include"Queue.h"
#include"Stack.h"//在全局定义⼀份单独的Stack
typedef struct Stack
{int a[10];int top;
}ST;void STInit(ST* ps){}
void STPush(ST* ps, int x){}int main()
{// 调⽤全局的 ST st1;STInit(&st1);STPush(&st1, 1);STPush(&st1, 2);printf("%d\n", sizeof(st1));// 调⽤zfy namespace的 zfy::ST st2;bzfy::STInit(&st2);zfy::STPush(&st2, 1);zfy::STPush(&st2, 2);printf("%d\n", sizeof(st2));return 0;
}
⑦C++标准库都放在⼀个叫std(standard)的命名空间中。
(2)命名空间的使用
编译查找⼀个变量的声明/定义时,默认只会在局部或者全局查找,不会到命名空间里面去查找。所以下面程序会编译报错。
#include<stdio.h>
namespace zfy
{int a = 0;int b = 1;
}int main()
{// 编译报错:error C2065: “a”: 未声明的标识符 printf("%d\n", a);return 0;
}
因此我们要想使用命名空间中定义的变量/函数,有三种方式:
①指定命名空间访问。项目中推荐这种方式。
// 指定命名空间访问
int main()
{printf("%d\n", zfy::a);return 0;
}
②using将命名空间中某个成员展开。项目中经常访问的不存在冲突的成员推荐这种方式。
// using将命名空间中某个成员展开
using zfy::b;int main()
{printf("%d\n", zfy::a);printf("%d\n", b);return 0;
}
③展开命名空间中全部成员。项目不推荐,冲突风险很大,因为可能会与全局中的变量冲突,导致编译报错,但在日常小练习时较方便,推荐使用。
// 展开命名空间中全部成员
using namespce zfy;int main()
{printf("%d\n", a);printf("%d\n", b);return 0;
}
六、C++的输入和输出
①<iostream>是Input Output Stream的缩写,是标准的输入、输出流库,定义了标准的输入、输 出对象。
②std::cin是 istream类的对象,它主要面向窄字符(narrow characters (of type char))的标准输输入流。
③std::cout 是ostream类的对象,它主要面向窄字符的标准输出流。
④std::endl是⼀个函数,流插入输出时,相当于插入⼀个换行字符加刷新缓冲区。
⑤>是流提取运算符。(C语言还用这两个运算符做位运算左移/右移)。
⑥使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动指定格式,C++的输入输出可以自动识别变量类型(本质是通过函数重载实现的),其实最重要的是 C++的流能更好的支持自定义类型对象的输入输出。
#include <iostream>
using namespace stdint main()
{int a = 0;double b = 0.1;char c = 'a';printf("%d %lf %c\n",a, b, c);//输出整型std::cout << a << std::endl;//输出浮点型std::cout << b << std::endl;//输出字符std::cout << c << std::endl;//还可以连接使用std::cout << a << " " << b << " " << c << " " << std::endl;//输出:0 0.1 a//输出换行符std::cout << "Hello\n";std::cout << a << '\n';std::cout << b << "\n";std::cout << c << std::endl;//在前面可以使用using namespace std;那么std::cout、std::endl可以写成cout、endl//输入时可以自动识别类型cin >> a;cin >> b >> c;//输出std::cout << a << std::endl;std::cout << b << " " << c << std::endl;return 0;
}
⑦ cout/cin/endl等都属于C++标准库,C++标准库都放在⼀个叫std(standard)的命名空间中,所以要通过命名空间的使用方式去用他们。
⑧⼀般日常练习中我们可以using namespace std,实际项目开发中不建议using namespace std。
这里我们没有包含<stdio.h>,仍可以使用printf和scanf,其实是在包含<stdio.h>时间接包含了。vs系列编译器是这样的,其他编译器可能会报错。
#include<iostream>
using namespace std;int main()
{// 在io需求⽐较⾼的地⽅,如部分⼤量输⼊的竞赛题中,加上以下3⾏代码,可以提⾼C++IO效率 ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);return 0;
}
七、缺省函数
①缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值。在调用该函数时,如果没有指定实参,则采用该形参的缺省值,否则使用指定的实参,缺省参数分为全缺省和半缺省参数。(有些地方把缺省参数也叫默认参数);
#include <iostream>
#include <assert.h>
using namespace std;//全缺省
void Func(int a = 0)
{cout << a << endl;
}int main()
{Func(); // 没有传参时,使⽤参数的默认值 Func(10); // 传参时,使⽤指定的实参 return 0;
}
②全缺省就是全部形参给缺省值,半缺省就是部分形参给缺省值。
③C++规定半缺省参数必须从右往左依次连续缺省,不能间隔跳跃给缺省值。
④带缺省参数的函数调用,C++规定必须从左到右依次给实参,不能跳跃给实参。
#include <iostream>
using namespace std;// 全缺省:全部形参给缺省值
void Func1(int a = 10, int b = 20, int c = 30)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl << endl;
}// 半缺省:部分形参给缺省值
//半缺省函数必须从右往左依次连续缺省,不能跳跃给缺省值
//错误写法:void Fun2(int a = 10, int b , int c = 20)
void Func2(int a, int b = 10, int c = 20)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl << endl;
}int main()
{Func1();Func1(1);Func1(1,2);Func1(1,2,3);//传参必须从左到右,不能跳跃给实参//错误写法:Fun1(,2,3);Func2(100);Func2(100, 200);Func2(100, 200, 300);return 0;
}
⑤函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省 值。
// Stack.h
#include <iostream>
#include <assert.h>
using namespace std;typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;
void STInit(ST* ps, int n = 4);//半缺省// Stack.cpp
#include"Stack.h"// 缺省参数不能声明和定义同时给,必须声明时给缺省值
void STInit(ST* ps, int n)
{assert(ps && n > 0);ps->a = (STDataType*)malloc(n * sizeof(STDataType));ps->top = 0;ps->capacity = n;
}// test.cpp
#include"Stack.h"
int main()
{ST s1;STInit(&s1);//如果不确定大小,默认为4//如果确定知道要插⼊1000个数据,初始化时⼀把开好,避免扩容 ST s2;STInit(&s2, 1000);return 0;
}
八、函数重载
①C++支持在同⼀作用域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者类型不同。(返回值不同不能作为重载条件)
#include<iostream>
using namespace std;// 1、参数类型不同
int Add(int left, int right)
{cout << "int Add(int left, int right)" << endl;return left + right;
}double Add(double left, double right)
{cout << "double Add(double left, double right)" << endl;return left + right;
}// 2、参数个数不同
void f()
{cout << "f()" << endl;
}void f(int a)
{cout << "f(int a)" << endl;
}// 3、参数类型顺序不同(本质上还是类型不同)
void f(int a, char b)
{cout << "f(int a,char b)" << endl;
}void f(char b, int a)
{cout << "f(char b, int a)" << endl;
}//!返回值不同不能作为重载条件,因为调⽤时也⽆法区分
//void fxx()
//{}//int fxx()
//{
// return 0;
//}
②这样C++函数调用就表现出了多态行为,使用更灵活。而C语言是不支持同⼀作用域中出现同名函数的。
// 下⾯两个函数构成重载
// 但是调⽤f()时,会报错,存在歧义,因为编译器不知道调⽤谁
void f1()
{cout << "f()" << endl;
}void f1(int a = 10)
{cout << "f(int a)" << endl;
}int main()
{Add(10, 20);Add(10.1, 20.2);f();f(10);f(10, 'a');f('a', 10);//到底是第一个函数,还是第二个函数,使用缺省值?(有歧义)return 0;
}
九、写在最后
我们刚接触C++,需要一定的知识储备才能进行学习。
敬请期待“入门基础(下)”~
相关文章:

C++——入门基础(上)
目录 一、C参考文档 二、C在工作领域的应用 三、C学习书籍 四、C的第一个程序 五、命名空间 (1)namespace的定义 (2)命名空间的使用 六、C的输入和输出 七、缺省函数 八、函数重载 九、写在最后 一、C参考文档 (1)虽…...

Spring事务失效
类内部访问导致事务不生效原因: 注解Transaction的底层实现是Spring AOP技术,而Spring AOP技术使用的是动态代理。spring事务失效的原因就是动态代理失效的原因: 对于static方法和非public方法,注解Transactional是失效的,因为不…...

Qt QLabel标签制作弹框效果,3s后缓慢自动消失
效果图 初始化说明 void InitStatusTips() {if (NULL statusTips_) {return;}statusTips_->setFixedSize(300, 80);//固定大小statusTips_->move((width() - statusTips_->width()) / 2, height() - 30 - statusTips_->height());//移动位置statusTips_->setA…...

JZ55 二叉树的深度
二叉树的深度_牛客题霸_牛客网 递归代码太简单-一行就可以,可以用二叉树的层序遍历,顺便温习下二叉树层序遍历的写法。 对应leetcode 104题,层序遍历对应leetcode-102自顶向下,leetcode-107自底向上 /* struct TreeNode {int val;struct Tre…...

视频号分销系统搭建教程,源代码+部署上线指南
目录 一、视频号分销是什么? 二、视频号分销系统怎么搭建? 1.系统架构设计 2.部署与上线 3.持续迭代与升级 三、部分代码展示 一、视频号分销是什么? 视频号分销系统是合集了视频号商家的产品,推广达人推广商家的产品可赚取…...

【python】cryptography库学习
【python】cryptography库学习 cryptography学习1-安装2-cryptography学习2.1-fernet的使用2.2-padding填充2.3-Hash2.4-ciphers(对称算法AES为例)2.5-asymmetric(非对称算法RSA为例)函数:generate_private_key类:RSAPrivateKey&a…...

解密!抖音百万粉丝博主三维地图视频都用到了什么GIS数据和技术
引言 在抖音上有许多诸如三维地图科普局、三维地图看世界和三维地图鉴赏等百万粉丝博主靠着三维地图科普城市、景区、人文和地理视频获赞百万,在我们浏览视频时犹如身临其境一般,那么制作这些视频需要什么GIS技术呢?如何利用MapMost技术自己…...

Python知识点:如何使用Kubernetes与Python进行容器编排
Kubernetes 是一个开源的容器编排平台,用于自动化容器化应用的部署、管理和扩展。结合 Python,你可以通过 Kubernetes API 和工具,如 kubectl 和 kubernetes-client 库,来编写和管理容器化应用。以下是如何使用 Kubernetes 和 Pyt…...

Markdown与Word中插入图片的方法及比较
在撰写文档时,无论是技术文档、博客还是学术论文,插入图片都是非常常见的需求。本文将对比两种流行的文本编辑工具——Markdown和Microsoft Word——在插入图片方面的异同点。 Markdown插入图片 如何插入图片 在Markdown中插入图片非常简单࿰…...

Vue3+Vite安装配置tailwindCss
考虑到官网不是很好访问,这里记录一下简单步骤方便小友查阅 1. 安装依赖 npm install -D tailwindcss postcss autoprefixer2. 初始化配置文件 npx tailwindcss init -p3.配置模板路径 /** type {import(tailwindcss).Config} */ export default {content: [&quo…...

大数据学习-Spark基础入门
一、Spark是什么? Stack Overflow的数据可以看出,2015年开始Spark每月的问题提交数量已经超越Hadoop,而2018年Spark Python版本的API PySpark每月的问题提交数量也已超过Hadoop。2019年排名Spark第一,PySpark第二;而十…...

C语言:链表插入
链表的插入分为头插入,中间插入和尾插入。 具体方法如下: #include<stdio.h> #include<stdlib.h>typedef struct node {int s;struct node* pnext; }list;list* addnode(list** pphead, list** ppend, int n) {list* ptemp malloc(sizeof…...

xss 一些例子
目录 XSS 1.Ma Spaghet!编辑 2.Jefff编辑 3.Ugandan Knuckles编辑 4.Ricardo Milos编辑 5.Ah Thats Hawt编辑 6.Ligma编辑 7.Mafia编辑 简单解法就是换一个函数 作者得原意解法 8.Ok, Boomer编辑 XSS 1.Ma Spaghet! 这里接收了一个somebody参数&…...

基于Docker compose部署Confluence 8.3.4及设置数据持久化存储的总结
基于Docker compose部署Confluence 8.3.4及设置数据持久化存储的总结 一、环境信息二、安装部署三、向导 介绍如何基于Docker、Docker Compose的方式安装部署Confluence 8.3.4,并且设置数据的持久化存储。 一、环境信息 操作系统:CentOS 7.9 Docker Ver…...

eNSP 华为交换机生成树协议
华为交换机生成树协议 生成树协议原理与作用 选举一个交换机作为根网桥(生成树的根),计算出到其他所有交换机的最佳路径,把备用路径的端口设为堵塞状态(逻辑上关闭备用路径),当最佳路径故障再…...

flutter事件与消息通知
事件与消息通知 一、原始指针事件(触摸事件) 命中测试 事件阶段:手指按下、手指移动、手指抬起事件冒泡,无法停止冒泡Listener 组件:监听原始触摸事件 onPointerDown:手指按下回调onPointerMove:手指移动回调onPointerUp:手指抬起回调onPointerCancel:触摸事件取消回…...

Oracle PL/SQL存储过程和函数简单示例
以下是关于Oracle PL/SQL存储过程和函数的一些问题和答案: 问题1:什么是Oracle PL/SQL? 答案:Oracle PL/SQL(Procedural Language Extensions to SQL)是Oracle对SQL的过程语言扩展,它是一种编…...

同态加密和SEAL库的介绍(十)CKKS 参数心得 2
写在前面: 本篇继续上篇的测试,首先针对密文深度乘法情况,虽然密文乘法本就是应该尽量避免的(时间和内存成本过高),更不用说深度乘法了,但是为了测试的完整性,还是做一下方便大家比对…...

Debug-021-el-table实现分页多选的效果(切换分页,仍可以保持前一页的选中效果)
前情提要: 这个功能实现很久了,但是一直没有留意如何实现,今天想分享一下。具体就是我们展示table数据的时候,表格中的数据多数情况是分页展示,毕竟数据量太多,分页的确是有必要的。那么我们有业务需要给表…...

FPGA开发——DS18B20读取温度并且在数码管上显示
一、简介 在上一篇文章中我们对于DS18B20的相关理论进行了详细的解释,同时也对怎样使用DS18B20进行了一个简单的叙述。在这篇文章我们通过工程来实现DS18B20的温度读取并且实现在数码管伤显示。 1、基本实现思路 根据不同时刻的操作,我们可以使用一个状…...

电流测量分流电阻
电流测量分流电阻 测量电流的设备称为安培计。大多数现代安培计测量已知电阻的精密电阻上的电压降。电流的计算使用欧姆定律:我五R 大多数电流表都内置电阻器来测量电流。但是,当电流对于电流表来说太高时,需要不同的设置。解决方案是将电流…...

MES系统:智能化排班排产的全面解决方案
MES(制造执行系统)管理系统通过集成多种先进技术、实时数据采集与分析、优化算法应用以及与其他系统的协同工作,实现了智能化排班排产功能。以下是该功能的详细实现方式: 数据集成与实时采集:MES系统与ERP、SCM、设备管…...

50道深度NLP和人工智能领域面试题+答案
编者按:分享一个很硬核的免费人工智能学习网站,通俗易懂,风趣幽默, 可以当故事来看,轻松学习。 什么是自然语言处理(NLP)?自然语言处理是一种人工智能领域,致力于使计算机…...

最小矩阵宽度(85%用例)C卷(JavaPythonC++Node.jsC语言)
给定一个矩阵,包含N*M个整数,和一个包含K个整数的数组。 现在要求在这个矩阵中找一个宽度最小的子矩阵,要求子矩阵包含数组中所有的整数。 输入描述: 第一行输入两个正整数N,M,表示矩阵大小。 接下来N行M列表示矩阵内容。 下一行包含一个正整数K。 下一行包含K个整数,…...

STM32数据按字符截取与转换
目录 1. 截取2. 转换 1. 截取 以SW,33,55,78,\r\n为例 char* pa,pb,pc,pd,pe; uint8_t usart5_rxsavebuf[] "SW,12,32,33,55,78,\r\n";strtok((char *)usart5_rxsavebuf, ","); pa strtok(NULL, ","); pb strtok(NULL, ","); pc …...

使用kubeadm快速部署一套K8S集群
一、Kubernetes概述 1.1 Kubernetes是什么 Kubernetes是Google在2014年开源的一个容器集群管理系统,Kubernetes简称K8S。 K8S用于容器化应用程序的部署,扩展和管理。 K8S提供了容器编排,资源调度,弹性伸缩,部署管理…...

【Kotlin】在Kotlin项目中使用AspectJ
前言 AOP编程在Java开发中是一个非常火热的话题,最著名的库为AspectJ Kotlin项目中,通过Gradle插件,也能够使用该库,这是我们下面讲解的重点 由于AspectJ的原理是在预编译阶段,通过插件修改代码,生成代理…...

web实现drag拖拽布局
这种拖拽布局功能其实在电脑操作系统或者桌面应用里面是经常使用的基础功能,只是有时候在进行web开发的时候,对这个功能需求量不够明显,但却是很好用,也很实用。能够让用户自己拖拽布局,方便查看某个区域更多内容&…...

Linux网络编程—listen、accept、connect
一、网络四件套 #include <sys/types.h> //头文件;这四个文件一包,基本网络就无问题了; #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> 二、listen 监听:将套…...

logback.xml自定义标签节点
logback.xml自定义标签节点 问题 <?xml version"1.0" encoding"UTF-8" ?> <configuration scan"true" scanPeriod"60 seconds" debug"false"><appender name"console" class"ch.qos.logb…...