目前在总结现代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. iOS - 截屏,view截图的基本方法

    推荐一个第三方好用的框架:SDScreenshotCapture #define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice cur ...

  2. Linq-string判断忽略大小写

    Coupon203Play play = dbContext.Coupon203Plays.Where(u => u.VerifyCode.Equals(verifyCode,StringCom ...

  3. Android井字游戏(二)游戏界面

    图片与代码可见书配套官网下载 1 棋盘 1.1  先将游戏界面所需的图片放于“drawable-xxhdpi”文件夹中,后缀xxhdpi表示超高密度. 然后将图片封装到drawable中一个名为til ...

  4. tp3.2分页功能

    后台 1.利用Page类和limit方法分页 $User = M('User'); // 实例化User对象 $count = $User->where('status=1')->coun ...

  5. WP8.1学习系列(第十六章)——交互UX之命令模式

    命令模式   在本文中 命令类型 命令放置 相关主题 你可以在应用商店应用的几个曲面中放置命令和控件,包括应用画布.弹出窗口.对话框和应用栏.在正确的时间选择合适的曲面可能就是易于使用的应用和很难使用 ...

  6. 【大数据系列】HDFS文件权限和安全模式、安装

    HDFS文件权限 1.与linux文件权限类型 r:read w:write x:execute权限x对于文件忽略,对于文件夹表示是否允许访问其内容 2.如果linux系统用户sanglp使用hado ...

  7. 【BZOJ5133】[CodePlus2017年12月]白金元首与独舞 矩阵树定理

    [BZOJ5133][CodePlus2017年12月]白金元首与独舞 题面:www.lydsy.com/JudgeOnline/upload/201712/div1.pdf 题解:由于k很小,考虑用 ...

  8. MVC @RenderBody、@RenderSection、@RenderPage、@Html.RenderPartial、@Html.RenderAction

    1.@RenderBody() 作用和母版页中的服务器控件类似,当创建基于此布局页面的视图时,视图的内容会和布局页面合并,而新创建视图的内容会通过布局页面的@RenderBody()方法呈现在标签之间 ...

  9. 使用pidstat监控资源使用

    linux可以使用pidstat命令监控系统资源,比如监控cup使用如下: pidstat -u 还可以使用 -r(内存) -d(硬盘)

  10. POJ-1157 LITTLE SHOP OF FLOWERS(动态规划)

    LITTLE SHOP OF FLOWERS Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 19877 Accepted: 91 ...