目前在总结现代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. Django restframwork教程之类视图(class-based views)

    我们也可以使用类的views写我们的API,我们将看到这是一个强大的模式,允许我们重用公共功能,让我们的代码整洁 使用Class-based Views重新改写我们的API 打开views.py文件, ...

  3. 【转载】如何从win8/8.1中文版(核心版)升级到win8/8.1专业版

    最近帮助很多同学从win8/8.1的基础版本 - 中文版(核心版)升级到了专业版,经过咨询,升级系统的最主要原因是中文版(核心版)的功能限制,因为基础版本阉割掉了很多常用的功能,比如组策略,计算机管理 ...

  4. WP8.1学习系列(第三章)——磁贴和锁屏通知

    一.创建默认磁贴 创建默认磁贴,不需要任何代码只有制作几张图片就可以了. 1.创建工程之后,在工程目录找到package.appxmanifest,打开它. 2.在应用程序栏,通知选项,选择徽章和图块 ...

  5. linux各种版本下载地址

    本文转载地址:http://52199999.blog.51cto.com/740826/290179 觉得好大家给顶顶,先谢谢了!呵呵 首先提供两个镜像站:http://mirrors.sohu.c ...

  6. node爬虫(转)

    我们先来看看今天的目标: mmjpg.com的美腿频道下的图片 一.实现步骤 使用superagent库来获取页面分析页面结构,使用cheerio 获取有效信息保存图片到本地开撸不断优化 这儿我们用到 ...

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

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

  8. Testlink自动执行用例小程序

    记得原来在一个公司时,具体很多原因,testlink上项目中的用例都需要执行形成漂亮的报告,但实际测试中又不需要去执行,所以就必须将用例根据上一次测试报告一个一个手工去贴结果刷用例,几百条用例,几天就 ...

  9. Xcode - 打开工程,提示No Scheme解决

    错误提示,如图: 解决思路:

  10. 关于*** WARNING L15: MULTIPLE CALL TO SEGMENT

    编写51程序的时候,有时候会在主函数和中断函数里面调用同一个函数,如果正的出现这种情况,编译器会提出 这种警告: *** WARNING L15: MULTIPLE CALL TO SEGMENT(重 ...