目前在总结现代C++的新特性,看了《深入理解C++11》这本书。

今天看到扩展的friend语法这一节,遇到了问题。本节电子版内容参见:https://book.2cto.com/201306/25354.html

未改良前的代码如代码清单2-21所示(在Linux下按照下面的编译指令能够通过),接着作者总结出了这种方法4点不好,给出了改良版代码(如代码清单2-22所示)。我要吐槽的是,反复试了好久,这改良版根本就不能够通过编译,感觉代码写的相当的鬼畜。

代码清单2-21

#include<iostream>
using namespace std; // 为了方便测试,进行了危险的定义
#ifdef UNIT_TEST
#define private public
#endif
class Defender {
public:
void Defence(int x, int y){}
void Tackle(int x, int y){} private:
int pos_x = 15;
int pos_y = 0;
int speed = 2;
int stamina = 120;
}; class Attacker {
public:
void Move(int x, int y){}
void SpeedUp(float ratio){} private:
int pos_x = 0;
int pos_y = -30;
int speed = 3;
int stamina = 100;
}; #ifdef UNIT_TEST
class Validator {
public:
void Validate(int x, int y, Defender & d){}
void Validate(int x, int y, Attacker & a){}
}; int main() {
Defender d;
Attacker a;
a.Move(15, 30);
d.Defence(15, 30);
a.SpeedUp(1.5f);
d.Defence(15, 30);
Validator v;
v.Validate(7, 0, d);
v.Validate(1, -10, a);
return 0;
}
#endif
// 编译选项:g++ 2-9-3.cpp -std=c++11 -DUNIT_TEST
代码清单2-22

 #include<iostream>
using namespace std; template <typename T> class DefenderT {
public:
friend T;
void Defence(int x, int y){}
void Tackle(int x, int y){} private:
int pos_x = 15;
int pos_y = 0;
int speed = 2;
int stamina = 120;
}; template <typename T> class AttackerT {
public:
friend T;
void Move(int x, int y){}
void SpeedUp(float ratio){} private:
int pos_x = 0;
int pos_y = -30;
int speed = 3;
int stamina = 100;
}; using Defender = DefenderT<int>; // 普通的类定义,使用int做参数
using Attacker = AttackerT<int>; #ifdef UNIT_TEST
class Validator {
public:
void Validate(int x, int y, DefenderTest & d){}
// 该行和下一行均报错:语法错误
void Validate(int x, int y, AttackerTest & a){}
//我在想这里的AttackerTest 是下面两行定义的,尝试把下面的两行提到前面错误变得更多了
}; using DefenderTest = DefenderT<Validator>; // 测试专用的定义,Validator类成为友元
using AttackerTest = AttackerT<Validator>; int main() {
DefenderTest d;
AttackerTest a;
a.Move(15, 30);
d.Defence(15, 30);
a.SpeedUp(1.5f);
d.Defence(15, 30);
Validator v;
v.Validate(7, 0, d) ;
//此处和下一行均报错:函数不接受3个参数
v.Validate(1, -10, a);
return 0;
}
#endif
// 编译选项:g++ 2-9-4.cpp -std=c++11 -DUNIT_TEST

最后修改方法

using DefenderTest = DefenderT<Validator>;  // 测试专用的定义,Validator类成为友元
using AttackerTest = AttackerT<Validator>;
把这两行提到
class Validator 之前,因为他的成员函数用到了这些定义
又因为 using DefenderTest = DefenderT<Validator>; 用到了 Valkidator 所以 要在这句话之前,前置声明一下 class Validator;

感谢hdt的帮助,问题帖来源点击此处

发现《深入理解C++11》中扩展的friend代码的错误的更多相关文章

  1. 理解ios 11中webview的视口

    iOS 11在状态栏区域带来了一些新的,也许是不直观的行为,这对使用Apache Cordova或Ionic等工具的开发人员尤为重要.特别是,这种行为变化会影响任何基于Web的应用程序,这些应用程序在 ...

  2. 从linux0.11中起动部分代码看汇编调用c语言函数

    上一篇分析了c语言的函数调用栈情况,知道了c语言的函数调用机制后,我们来看一下,linux0.11中起动部分的代码是如何从汇编跳入c语言函数的.在LINUX 0.11中的head.s文件中会看到如下一 ...

  3. JDK 11中的ZGC-一种可扩展的低延迟垃圾收集器

    # 背景正如我们所知道的在JDK 11中即将迎来ZGC(The Z Garbage Collector),这是一个处于实验阶段的,可扩展的低延迟垃圾回收器.本文整合了外网几篇介绍ZGC的文章和代码. ...

  4. C++11 中值得关注的几大变化(网摘)

    C++11 中值得关注的几大变化(详解) 原文出处:[陈皓 coolshell] 源文章来自前C++标准委员会的 Danny Kalev 的 The Biggest Changes in C++11 ...

  5. 深入理解Java虚拟机--中

    深入理解Java虚拟机--中 第6章 类文件结构 6.2 无关性的基石 无关性的基石:有许多可以运行在各种不同平台上的虚拟机,这些虚拟机都可以载入和执行同一种平台无关的字节码(ByteCode),从而 ...

  6. 深入理解C++11【5】

    [深入理解C++11[5]] 1.原子操作与C++11原子类型 C++98 中的原子操作.mutex.pthread: #include<pthread.h> #include <i ...

  7. 深入理解C++11【4】

    [深入理解C++11[4]] 1.基于范围的 for 循环 C++98 中需要告诉编译器循环体界面范围.如for,或stl 中的for_each: int main() { ] = { , , , , ...

  8. 深入理解C++11【3】

    [深入理解C++11[3]] 1.POD类型 Plain Old Data. Plain 表示 了POD是个普通的类型.C++11将POD划分为两个基本概念的合集: 1)平凡的(trivial) 2) ...

  9. 深入理解C++11

    [深入理解C++11] 1.很多 现实 的 编译器 都 支持 C99 标准 中的__ func__ 预定 义 标识符 功能, 其 基本 功能 就是 返回 所在 函数 的 名字. 编译器 会 隐式 地 ...

随机推荐

  1. 关于Android开发中使用的XML

    1.布局 FrameLayout: 以堆叠方式显示一个或多个子视图. GridLayout: 将子视图按行和列排列. LinearLayout: 将所有子视图排列成一行或一列. RelativeLay ...

  2. [sql异常]SQL Server 阻止了对组件 'Ad Hoc Distributed Queries' 的

    //执行远程数据库表查询 SELECT * FROM OPENDATASOURCE('SQLOLEDB', 'Data Source=数据库地址;User ID=sa;password=sa' ).n ...

  3. Building Boost for Android with error “cannot find -lrt”

    编辑tools/build/src/tools/gcc.jam rule setup-threading ( targets * : sources * : properties * ){ local ...

  4. rsyslog local0-local7的用法

    很多时候我们需要将一个服务的日志文件导向一个指定的文件,这个时候可以设置log-facility 如在dhcpd.conf中配置 1 : update log-facility in the dhcp ...

  5. MVC验证

    前言 MVC自己的验证机制,通过一个案例记录学习的成果. 首先,model代码如下: public class Students    {        [Display(Name = "I ...

  6. 如何玩facebook app上的H5游戏

    一.下载facebook app facebook链接 二.下载vpn 国内是访问不了的,必须vpn 因为vpn被封了厉害 我随便百度了个狸猫加速器,没付费,时断时续... 没有推荐的vpn,哪位大佬 ...

  7. iOS 循环引用 委托 (实例说明)

    如何避免循环引用造成的内存泄漏呢: 以delegate模式为例(viewcontroller和view之间就是代理模式,viewcontroller有view的使用权,viewcontroller同时 ...

  8. 在pycharm中运行nose测试框架

    之前一直在pydev上或命令行上运行nosetests. pycharm上如果运行nosetests,在看了管网后,总结果如下: 全新的pycharm: 填加完成后,打开你要的脚本,运行,即可以以no ...

  9. 通过Adb 查看当前正在运行的Activity.

    extends:http://www.cnblogs.com/tt_mc/p/4269833.html adb shell dumpsys activity activities | sed -En ...

  10. Xcode - xcode-select: error: tool 'xcodebuild' requires Xcode报错解决方案

    用mac 自带的终端执行的命令,安装安装Vapor和toolbox 安装指令: macdeMacBook-Pro:~ mac$ curl -sL check.vapor.sh| bash 结果报这个错 ...