读《google C++风格指南》有感


1. 复习内容

1.1 匿名命名空间

字面意思:声明命名空间时忽略名字
编译器内部会为这个命名空间生成一个唯一的名字和using指令

namespce {
    char c;
    int i;
    double d;
 }

所以上面的代码在编译器内部类似于:

 namespace __UNIQUE_NAME_ {
     char c;
     int i;
     double d;
     }
 using namespace __UNIQUE_NAME_;

它和静态变量的相似之处?
匿名命名空间也具有内连接属性,也就是说名称的作用域被限制在当前文件中,无法在其他文件使用extern来扩展作用域
它和静态变量相比更优在哪?
对于多个同一文件的标识符函数只需要用一个匿名空间来声明,不需要多次输入static

1.2 如何引用命名空间
// 方式一
ace::Mutex mutex;
// 方式二
using ace::Mutex;
// 方式三
using namespace ace;
  • 方式一
    只是在必要的时候运用域运算符::来引用指定空间里的标识符。
    适用于:当前编译单元内引用ace内的标识符不多且使用次数不多
  • 方式二
    只引入ace::Mutex一个标识符
    适用于:当前编译单元内ace::Mutex使用次数较多的情况
  • 方式三
    把ace里的全部标识符都引入当前命名空间中,此后ace内所有的标识符对于当前空间都是可见的
    适用于:当前编译单元内使用ace内的标识符较多,且不会出现标识符冲突的问题

对于上面三种方式的选择应由一到三,因为越往后产生命名冲突的可能越大

1.3 override与final
  • override:指定一个虚函数覆写另一个虚函数
    在成员声明或定义中,override确保该函数为虚并且复写来自基类的虚函数,若不是就会出现编译错误
  • final:指定派生类不能覆写虚函数,或类不能被继承
    在虚函数声明或定义中,final确保函数为虚且不可被派生类复写
    在类定义中,final指定此类不能被派生
1.4 访问者模式
  • 定义:封装某些作用于某数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作
  • 自己的理解:在衣服店定制了几套衣服,成衣后我又想对某件衣服进行改变,但是已经不能改变衣服了,所以收到衣服后,我只能针对我想改变的那件,新增加一些小搭配(丝巾等等)
  • 含有角色:
    抽象访问者 访问者 抽象元素类 元素类 结构对象
package yanbober.github.io;

import java.util.ArrayList;
import java.util.List;

//Vistor(抽象访问者)
interface Vistor {
    void visit(ConcreteElementNodeA node);
    void visit(ConcreteElementNodeB node);
}
//ConcreteVisitor(具体访问者)
class ConcreteVisitorA implements Vistor {
    @Override
    public void visit(ConcreteElementNodeA node) {
        System.out.println(node.operationA());
    }

    @Override
    public void visit(ConcreteElementNodeB node) {
        System.out.println(node.operationB());
    }
}

class ConcreteVisitorB implements Vistor {
    @Override
    public void visit(ConcreteElementNodeA node) {
        System.out.println(node.operationA());
    }

    @Override
    public void visit(ConcreteElementNodeB node) {
        System.out.println(node.operationB());
    }
}
//Element(抽象元素)
abstract class ElementNode {
    public abstract void accept(Vistor vistor);
}
//ConcreteElement(具体元素)
class ConcreteElementNodeA extends ElementNode {
    @Override
    public void accept(Vistor vistor) {
        vistor.visit(this);
    }

    public String operationA() {
        return "ConcreteElementNodeA";
    }
}

class ConcreteElementNodeB extends ElementNode {
    @Override
    public void accept(Vistor vistor) {
        vistor.visit(this);
    }

    public String operationB() {
        return "ConcreteElementNodeB";
    }
}
//ObjectStructure(对象结构)
class ObjectStructure {
    private List<ElementNode> nodeList = new ArrayList<>();

    public void action(Vistor vistor) {
        for (ElementNode node : nodeList) {
            node.accept(vistor);
        }
    }

    public void add(ElementNode node) {
        nodeList.add(node);
    }
}
//客户端
public class Main {
    public static void main(String[] args) {
        ObjectStructure objectStructure = new ObjectStructure();
        objectStructure.add(new ConcreteElementNodeA());
        objectStructure.add(new ConcreteElementNodeB());

        Vistor vistor = new ConcreteVisitorA();
        objectStructure.action(vistor);
    }
}

参考:
设计模式(行为型)之访问者模式(Visitor Pattern)
23种设计模式(9):访问者模式

1.5 何时捕获异常

我们只能捕获我们能够处理的异常,能够恢复的异常将它捕获后恢复,像不能恢复的如,越界等就不要捕获了。
对使用 C++ 异常处理应具有怎样的态度?

1.6 可重入函数
1.7 杂项
  • explicit构造函数:指定构造函数或转换函数为显式,即它不能用于隐式转换和复制初始化
  • 静态存储周期:static用于声明对象拥有静态存储期
  • POD(Plain Old Data):该类型包括标量类型,c/c++的基本类型,用户自定义的类类型(这里的类必须是无析构函数和构造函数/拷贝构造函数的类,其实也就相当于struct)
  • const_cast:用来移除变量的cv限定符
  • volatile:一般编译器在访问变量时,都会对变量进行优化。也就是不会每一次都去变量的内存中读数据,编译器会把变量值存在「寄存器」中,在下一次查询时直接到此取数据,这样访问速度就大大增加。
    而volatile修饰的变量,编译器每一次查询都会去内存中读取数据。它常用于多线程编程,当一个线程改变变量的值的时候,「寄存器」的值可能还未更新,所以必须从内存中读数据读到的才是真实的数据。
  • mutable:常用于不影响类的外部可变状态的成员,该成员在const函数内依旧可被修改
    下面是它在lambda表达式中的使用:
    虽然看起来修改了x,其实只是修改了x的拷贝
int x{0};
auto f1 = [=]() mutable {x = 42;};  // okay, 创建了一个函数类型的实例
auto f2 = [=]()         {x = 42;};  // error, 不允许修改按值捕获的外部变量的值
  • std::function:通用多态的函数封装器,它的实例可以存储,复制及调用任何可调用目标
// 存储自由函数
std::function<void(int)> f_display = print_num;
f_display(-9);
 
// 存储 lambda
std::function<void()> f_display_42 = [](){ print_num(42); };
f_display_42();
 

2. 代码风格的思考(仅针对客户端)

2.1 在别人代码上进行迭代
  • 注意不要破坏别人原有的风格,对函数命名/变量命名应与前人统一
  • 修改之前应该仔细看看代码的结构,不要把本来耦合度很低的代码改成了耦合度极高的代码
2.2 自己写代码
  • 在做csd时就思考好节点的构造
  • 低耦合
  • 代码简洁,清楚
  • 命名易于理解,别人在看你代码时,可以通过命名直接明白函数需要做什么
  • 考虑内存!考虑内存!需要做缓存的就做缓存

下面以这个页面来对代码做一个梳理:
首先有一个头部主要是放活动图片/标题等,中部是一个横向scroll,上面的btn可以刷新下面的纵向scroll里的节点信息


  • 首先拿到页面所需要信息(initData)
  • 根据信息从上往下在代码中对页面进行展示(initView)
  • 思考scroll是否需要做缓存,在这里我只对纵向scroll做了缓存
  • 初始化横向scroll,注册回调事件来刷新纵向scroll(initMiddleScroll,updateMiddleScroll)
  • 定义两个table:tableItemsSel 和 tableItemsSpare(用于存储缓存数据)
  • 封装纵向scroll的信息,使用一个table封装,这里的point用于等会插入缓存table(initScrollData)
local tableItemsSel = {
  { data = data,
    point = nil,
    pos = {x = 0,y = 0}
}
}
  • 初始化纵向scroll,计算节点位置,更新tableItemsSel.pos(initScroll)
  • 填充纵向scroll

设定一个值为预加载范围,如果在范围内就让节点可见,不在范围内就让节点不可见且插入缓存tableItemsSpare

local scrollH = scroll的高度
local tableShowH = {beginY = math.max(0,scroll的y轴偏移-0.5*scrollH),endY = scroll的y轴偏移+1.5*scrollH,}

白色区域为我们的初始可视区域,红色区域就是我们现在扩大了的可视区域,超过这个可视区域,就让节点不可见且插入缓存tableItemsSpare


if v.pos.y < tableShowH.beginY or v.pos.y > tableShowH.endY then
                v.point:setVisible(false)
                table.insert(self.tableItemsSpare,v.point)
                v.point = nil
end

如果缓存数组里有节点就取出设为可见,再初始化它。否则新建节点


  • 设置scroll回调事件去重新填充scroll
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容