effective C++ (Item2) Prefer <iostream> to <stdio.h>

本文深入探讨了C++类模板中友元声明的三种形式及其应用,包括普通友元、一般模板友元关系和特定模板友元关系,解释了它们如何影响类的访问性和功能实现,并对比了它们与普通非模板类或函数的关系。此外,文章还讨论了声明的依赖性及全局作用域下的潜在名称冲突问题。

  type safety and extensibility are cornerstones of the C++ way of life.

 int i;

Rational r;

cin >> i >> r;

cout << i << r;

if this code is to compile, there must be functions operator >> and operator << that can work with an object Rational.if these functions are missing,it's an error;

there are some situations in which it may make sense to fall back on the tried and true

first  some implementation of iostream operations are less efficient than the corresponding c stream operations;

Second the iostream library was modified in some rather fundamental ways during the course of its standardization,so applications that must be maximally portable may discover that different vendor support different approximations to the standard

Third because the classes of the iostream library have constructors and the function in <stdio.h> do not,there are rare occasions involving the initialization order of static objects when the standard c library may be more useful simply because you know that you can always call it with impunity


There is no such things as <iostream.h>,the standardization commitee eliminated it in favor of <iostream> when they truncated the names of the other non-c standard header names

if your compiler support both <iostream> and <iostream.h>,the header are subtle different,in particular, if you #include<iostream>,you get the elements of iostream library ensconced within the namespace std;but if you #include<iostream.h>,you get those same elements at global scope,Get them at global scope can lead to name conflicts,precisely the kinds of name conflicts the use of namespace is designed to prevent,besides,<iostream> is less to type than <iostream.h>. 

 

 

appendix:类模板中得友元声明
在类模板中可以出现三种友元声明,每一种都声明了与一个或多个实体的友元关系
1 普通非模板类或函数的友元声明,将友元关系授予明确指定的类或函数
2 类模板或函数模板的友元声明,授予对友元所有实例的访问权
3 只授予对类模板或函数模板的特定实例的访问权的友元声明
1 普通友元
非模板类或非模板函数可以是类模板的友元
    template <class Type> class Bar
    {
             .........
            friend class Foobar;
            friend  void fcn();
     }
这个声明是说,FooBar的成员和fcn函数可以访问Bar类的任意实例的Private成员和Protected成员
2 一般模板友元关系
友元可以是类模板或函数模板
template <class Type >  class Bar
{
    template<class T> friend class Fool;
    template<class T> friend void temp1_fcn1(const T& );
   ...........
}
这些友元声明的使用与类本身的类型形参,该类型形参指的是Fool和temp_fcn1的类型形参,在这两种情况下,都将
没有数目限制的类和函数设为Bar的友元,Fool的友元声明是说,Fool的任意实例都可以访问Bar的任意实例的私有元素,
类似地,temp1_fcn1的任意实例可以访问Bar的任意实例。
这个友元声明在Bar与其友元Fool和temp1_fcn1的每个实例之间建立一对多的映射。对Bar的每个实例而言,Foo1和Temp1_fcn1的
所有实例都是友元
3 特定的模板友元关系
类也可以只授予对特定实例的访问权
template <class T> class Foo2;
template <class T> void temp1_fcn2(const T&);
template <class Type> class Bar
{
    friend class Foo2(char*);
 friend void temp1_fcn2(char* const &);
 ........
};
即使Foo2本身是类模板,友元关系也只扩展到Foo2的形参类型为char*的特定实例,类似的,temp1_fcn2的友元声明是说,
只有形参类型为char*的函数实例时Bar类的友元,形参类型为char*的Foo2和temp1_fcn2的特定实例可以访问Bar的每一个实例。

下面形式的友元声明更为常见
 template <class T> class Foo3;
 template <class T> void temp1_fcn3(const T&);
 template <class Type> class Bar
 {
     friend class Foo3(Type);
  friend void temp1_fcn3<Type> (const Type&);
  ..........
 }
 这些友元定义了Bar的特定实例与使用同一模板实参的Foo3和temp1_fcn3的实例之间的友元关系,每个Bar实例有一个相关的Foo3和temp1_fcn3
 友元
 Bar <int> bi;      Foo3<int> and temp1_fcn3(int) are friends;
 Bar <string> bs;   Foo3<string> and temp1_fcn3(int)are friends;
 只有给定Bar实例相同模板实参的那些Foo3或temp1_fcn3版本是友元,因此Foo3<int> 可以访问Bar<int>的私有部分,但不能访问Bar<string>
 或任意其他Bar实例的私有部分。
 
 4 声明的依赖性
 当授予对给定模板的所有实例的访问权的时候,在作用域中不需要存在该模板或函数模板的声明。实质上,编译器将友元声明当做类或函数的声明对待
 想要限制对特定实例化的友元关系时,必须在可以用于友元声明之前声明类或函数:
  template <class T> class A;
  template <class T> class B
  {
       friend class A<T>  // ok A is known to be a template
    friend class C;     // ok,C must be an ordinary nontemplate class;
    template class <class S> friend class D; // OK D is a template
    friend class E<T>;  //error    E wasn't declared as a template
    friend class F<int> // error   F wasn't declared as a template
    ........
  };
  如果没有事先告诉编译器该友元是一个模板,则编译器将认为该友元是一个普通的非模板类或非模板函数。

 

 

 

<think>我们面对的问题:项目出现IllegalArgumentException异常,提示"LoggerFactory is not a Logback LoggerContext but Logback is on the classpath",但在pom.xml中只配置了log4j的依赖(如slf4j-log4j12)。这表明虽然我们想要使用Log4j,但类路径中意外出现了Logback的依赖,导致SLF4J绑定冲突。 解决方案的核心:移除类路径中意外的Logback依赖,确保SLF4J绑定到我们期望的Log4j实现。 具体步骤: 1. **检查依赖树,找出引入Logback的依赖** 执行Maven命令分析依赖树: ```bash mvn dependency:tree -Dincludes=ch.qos.logback ``` 这个命令会列出所有包含`ch.qos.logback`的依赖,从而找到是哪个依赖传递引入了Logback。 2. **在pom.xml中排除Logback依赖** 假设我们发现是某个依赖(例如`spring-boot-starter-web`)传递引入了Logback,则在该依赖中排除Logback: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> </exclusion> <!-- 可能还需要排除logback-core --> <exclusion> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> </exclusion> </exclusions> </dependency> ``` 3. **确保正确的Log4j依赖存在** 既然你希望使用Log4j,那么需要确保项目中已经包含了Log4j的SLF4J绑定和Log4j本身的依赖。通常需要以下两个依赖: ```xml <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.30</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> ``` 4. **验证依赖冲突是否解决** 再次运行依赖树检查命令,确保Logback已经被移除,同时Log4j的绑定存在: ```bash mvn dependency:tree -Dincludes=ch.qos.logback,org.slf4j,log4j ``` 5. **处理WebLogic等应用服务器的特殊情况** 如果在WebLogic上部署,即使排除了依赖,服务器自带的日志库仍可能引起冲突。此时需要在`WEB-INF/weblogic.xml`中配置优先使用应用内的SLF4J实现: ```xml <weblogic-web-app> <container-descriptor> <prefer-application-packages> <package-name>org.slf4j.*</package-name> </prefer-application-packages> </container-descriptor> </weblogic-web-app> ``` 6. **清理和重新构建** 执行Maven清理并重新构建项目: ```bash mvn clean install ``` 7. **运行时验证** 启动应用,观察日志中SLF4J的绑定信息,应该看到类似这样的输出: ``` SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory] ``` 注意:如果项目中使用了Spring Boot,注意Spring Boot默认使用Logback,需要排除其默认日志依赖并引入Log4j的starter(如果使用Log4j2则另有配置)。但根据你的描述,你只配置了log4j(可能是Log4j1.x),所以按照上述步骤排除Logback即可。 如果按照上述步骤操作后问题仍然存在,请再次检查是否有其他依赖间接引入了Logback,或者是否有其他SLF4J绑定(如`slf4j-simple`)存在,一并排除。 §§相关问题§§ 1. 如何检测项目中是否存在多个SLF4J绑定? 2. 在Maven中如何排除所有传递依赖中的特定库? 3. WebLogic服务器如何配置类加载器优先级? </think> ### 解决"LoggerFactory is not a Logback LoggerContext"问题的完整方案 #### 一、问题分析 当pom.xml中仅配置了Log4j依赖(如`slf4j-log4j12`)却出现Logback冲突时,根本原因是**存在隐藏的Logback依赖**[^1][^2]。典型场景包括: 1. 依赖传递:其他库(如Spring Boot)间接引入了Logback 2. 容器自带:Tomcat/WebLogic等容器内置Logback 3. IDE缓存:残留的旧依赖未被完全清除 #### 二、解决方案步骤 ##### 1. 显式排除Logback依赖 在pom.xml中添加全局排除规则: ```xml <dependencyManagement> <dependencies> <!-- 全局排除Logback --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.11</version> <scope>provided</scope> <!-- 阻止打包 --> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.11</version> <scope>provided</scope> </dependency> </dependencies> </dependencyManagement> ``` ##### 2. 检查并清理传递依赖 使用Maven命令定位冲突源: ```bash mvn dependency:tree -Dincludes=logback,slf4j ``` 若发现类似输出,需在对应依赖中添加排除: ```diff <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> + <exclusions> + <exclusion> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + </exclusion> + </exclusions> </dependency> ``` ##### 3. 强制指定Log4j为唯一绑定 确保pom.xml包含正确的Log4j配置: ```xml <!-- SLF4J到Log4j的桥接 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.36</version> </dependency> <!-- Log4j核心 --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> ``` ##### 4. 添加log4j.properties配置 在`src/main/resources`创建日志配置文件: ```properties # log4j.properties log4j.rootLogger=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n ``` ##### 5. 容器部署特殊处理(WebLogic/Tomcat) 在`WEB-INF/weblogic.xml`中添加: ```xml <container-descriptor> <prefer-application-packages> <package-name>org.slf4j.*</package-name> <package-name>ch.qos.logback.*</package-name> </prefer-application-packages> </container-descriptor> ``` #### 三、验证与清理 1. **清理构建缓存**: ```bash mvn clean install -U ``` 2. **检查最终依赖**: ```bash mvn dependency:build-classpath | grep logback # 应无输出结果 ``` 3. **启动日志验证**: ``` SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory] ``` > **重要提示**:若使用IDEA开发,需执行以下操作: > 1. File → Invalidate Caches > 2. 删除`~/.m2/repository/ch/qos/logback`本地仓库缓存 #### 四、备选方案 若仍存在冲突,改用SLF4J简单日志实现: ```xml <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.36</version> </dependency> ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值