[C++] 编程实践之1: Google的C++代码风格3:类

C++:C++代码风格指南--Google(未完待续) 所谓「前置声明」(forward declaration)是类、函数和模板的纯粹声明,没伴随着其定义. 阅读详情

##类
  类是C++中代码的基本单元。显然它们被广泛使用。本节列举了在写一个类时的主要注意事项。
###构造函数的职责

不要在构造函数中进行复杂的初始化(尤其是那些有可能失败或者需要调用虚函数的初始化)。

定义:

  • 在构造函数体中进行初始化操作。

优点:

  • 排版方便,无需担心类是否已经初始化。

缺点:

  • 构造函数中很难上报错误,不能使用异常。
  • 操作失败会造成对象初始化失败,进入不确定状态。
  • 如果在构造函数内调用了自身的虚函数,这类调用是不会重新定向到子类的虚函数实现,即使当前没哟子类化实现,将来仍然是隐患。
  • 如果有人创建该类的全局变量(虽然违背了上节提到的规则),构造函数将先main()一步被调用,有可能破坏构造函数中暗含的假设条件。例如gflags尚未初始化。

结论:

  • 构造函数不得调用虚函数,或尝试报告一个非致命错误。如果对象需要进行有意义的(non-trivial)初始化,考虑使用明确的Init()方法或者使用工厂模式。

###初始化

如果类中定义了成员变量,则必须在类中为每个成员变量提供初始化函数或定义一个构造函数。若未声明构造函数,则编译器会生成一个默认的构造函数,这有可能导致某些成员变量未被初始化或被初始化为不恰当的值。

定义:

  • new一个不带参数的类对象时,会调用这个类的默认构造函数。用new[]创建数组时,默认构造函数则总是被调用。在类成员里面进行初始化是指声明一个成员变量的时候使用一个结构例如int _count = 17或者string _name{“abc”}来替代int _count或者string _name这样的形式。

优点:

  • 用户定义的默认构造函数将在没有提供初始化操作时将对象初始化。这样就保证了对象在被构造之时就处于一个有效且可用的状态,同时保证了对象在被创建时就处于一个显然“不可能”的状态,以此帮助调试。

缺点:

  • 对代码编写者来说,这是多余的工作。如果一个成员变量在声明时初始化又在构造函数里用相同的方式初始化,有可能造成混乱,因为构造函数中的值会覆盖掉声明中的值。

结论:

  • 简单的初始化用类成员初始化完成,尤其是当一个成员变量要在多个构造函数里用相同的方式初始化的时候。
  • 如果你的类中有成员变量没有在类里面进行初始化,而且没有提供其它构造函数,你必须定义一个(不带参数)默认构造函数,把对象的内部状态初始化成为一致/有效的值。这无疑是一个更合理的方式。这么做的原因是:
    • 如果你没有提供其它构造函数,又没有定义默认构造函数,编译器将为你自动生成一个,编译器生成的构造函数并不会对对象进行合理的初始化。
    • 如果你定义的类继承现有类,而你又没有增加新的成员变量,则不需要为新类定义默认构造函数。

###显式构造函数

对单个参数的构造函数使用C++关键字explicit。

定义:

  • 通常,如果构造函数只有一个参数,可看成是一种隐式转换。打个比方,如果你定义了Foo:Foo(string name),接着把一个字符串传给一个以Foo对象为参数的函数,构造函数Foo:Foo(string name)将被调用,并将该字符串转换为一个Foo的临时对象传给调用函数。看上去很方便,但如果你并不希望通过转换生成一个新对象的话,麻烦也随之而来。为避免构造函数被调用造成隐式转换,可以将其声明为explicit。
  • 除单参数构造函数之外,这一规则也适用于除第一个参数以外的其它参数都具有默认参数的构造函数,例如Foo:Foo(string name, int id = 42)。

优点:

  • 避免不合时宜的变换。

缺点:

  • 无。

结论:

  • 所有单参数的构造函数都必须是显式的,在类定义中,将关键字explicit加到单参数构造函数之前:explicit Foo(string name)。
  • 例外:在极少数情况下,拷贝构造函数可以不声明成explicit,作为其它类的透明包装的类也是特例之一,类似的例外情况应在注释中明确说明。
  • 最后,只有std::initializer_list的构造函数可以是非explicit,以允许你的类型可以使用列表初始化的方式进行赋值,例如:
MyType m = {1, 2};
MyType MakeMyType() { return {1, 2}; }
TakeMyType({1, 2});

###可拷贝类型和可移动类型

如果你的类型需要,就让它们支持拷贝/移动。否则,就把隐式产生的拷贝和移动禁用。

定义:

  • 可拷贝类型通常允许对象在初始化时得到来自相同类型的另一对象的值,或在赋值时被赋予相同类型的另一对象的值,同时不改变源对象的值。对于用户定义的类型,拷贝操作一般通过拷贝构造函数与拷贝赋值操作符(=)定义。string类型就是一个可拷贝类型的例子。
  • 可移动类型允许对象在初始化时得到来自相同类型的临时对象的值,或在赋值时被赋予相同类型的临时对象的值(因此所有可拷贝对象也是可移动的)。std:unique_ptr就是一个可移动但不可复制的对象的例子。对于用户定义的类型,移动操作一般是通过移动构造函数和移动赋值操作符实现的。
  • 拷贝/移动构造函数在某些情况下会被编译器隐式调用。例如通过传值的方式传递对象。

优点:

  • 可移动及可拷贝类型的对象可以通过传值的方式进行传递或者返回,这使得API更简单、更安全也更通用。与传指针和引用不同,这样的传递不会造成所有权、生命周期、可变性等方面的混乱,也就没必要再协议中予以明确。这同时也防止了客户端与实现在非作用域内的交互,使得它们更容易被理解与维护。这样的对象可以和需要传值操作的通用API一起使用,例如大多数容器。
  • 拷贝/移动构造函数与赋值操作一般来说要比它们的各种替代方案,比如Clone(), CopyFrom()或者Swap()更容易定义,因为它们能通过编译器产生,无论是隐式的还是通过“=”默认。这种方式很简洁,也保证所有数据成员都会被复制。拷贝与移动构造函数一般也更高效,因为它们不需要堆的分配或者是单独的初始化和赋值步骤。同时,对于省略不必要的拷贝这样的优化它们也更加合适。
  • 移动操作允许隐式且高效地将源数据转移出右值对象,这有时能让代码风格更加清晰。

缺点:

  • 许多类型都不需要拷贝,为它们提供拷贝操作会让人迷惑,也显得荒谬而不合理。为基类提供拷贝/赋值操作时有害的,因为在使用它们时会造成对象的切割。默认的或者随意的拷贝操作实现可能使不正确的,这往往导致令人困惑并且难以诊断的错误。
  • 拷贝构造函数是隐式调用的,也就是说,这些调用很容易被忽略。这回让人迷惑,尤其是对那些所用语言约定或强制要求传引用的程序员来说更是如此。同时,这从一定程度上说会鼓励过度拷贝,从而导致性能上的问题。

结论:

  • 如果需要,就让你的类型可拷贝/可移动。作为一个经验法则,如果对于你的用户来说这个拷贝操作不是一眼就能看出来的,那就不要把类型设置为可拷贝。如果让类型可拷贝,一定要同时给出拷贝构造函数和赋值操作的定义。如果让类型可拷贝,同时移动操作的效率高于拷贝操作,那么就把移动的两个操作(移动构造函数和赋值操作)也给出定义。如果类型不可拷贝,但是移动操作的正确性对用户显然可见,那么把这个类型设置为只可移动并定义移动的两个操作。
  • 建议通过=default定义拷贝和移动操作。定义非默认的移动操作目前需要异常。时刻记得检测默认操作的正确性。由于存在对象切割的风险,不要为任何有可能有派生类的对象提供赋值操作或者拷贝/移动构造函数(当然也不要继承有这样的成员函数的类)。如果你的基类需要可复制属性,请提供一个public virtual Clone()和一个protected的拷贝构造函数以供派生类实现。
  • 如果你的类不需要拷贝/移动操作,请显示地通过=delete或其它手段禁用之。

###委派和继承构造函数

在能够减少重复代码的情况下使用委派和继承构造函数。

定义:

  • 委派和继承构造函数是由C++11引进为了减少构造函数重复代码而开发的两种不同的特性。通过特殊的初始化列表语法,委派构造函数允许类的一个构造函数调用其它的构造函数,例如:
X::X(const string& name) : name_(name) {
	...
}

X:X():X("") {}
  • 继承构造函数允许派生类直接调用基类的构造函数,一如继承基类的其它成员函数,而无需重新声明当基类拥有多个构造函数时这一功能尤其有用。例如下面的代码片段。如果派生类的构造函数只是调用基类的构造函数而没有其它行为时,这一功能特别有用。
class Base {
public:
	Base();
	Base(int n);
	Base(const string& s);
	...
}

class Derived : public Base {
public:
	using Base::Base;  // Base's constructors are redeclared here
}

优点:

  • 委派和继承构造函数可以减少荣誉代码,提高可读性。委派构造函数对Java程序员来说并不陌生。

缺点:

  • 使用辅助函数可以预估出委派构造函数的行为。如果派生类和基类相比引入了新的成员变量,继承构造函数就会让人迷惑,因为基类并不知道这些新的成员变量的存在。

结论:

  • 只在能够减少冗余代码,提高可读性的前提下使用委派和继承构造函数。如果派生类有新的成员变量,那么使用继承构造函数时要小心。如果在派生类中对成员变量使用了类内部初始化(指在定义的时候就初始化)的话,继承构造函数还是适用的。

###结构体 vs. 类

仅当只有数据时使用struct,其它一概使用class。

说明:

  • 在C++中struct和类关键字几乎含义一样。我们为这两个关键字添加我们自己的语义理解,以便未定义的数据类型选择合适的关键字。
  • struct用来定义包含数据的被动式方式,也可以包含相关的常量,但除了存取数据成员之外,没有别的函数功能。并且存取功能是通过直接访问位域,而非函数的调用。除了构造函数,析构函数,Initialize(),Reset(),Validate()等类似的函数外,不能提供其它功能的函数。
  • 如果需要更多的函数功能,class更适合。如果拿不准,就用class。
  • 为了和STL保持一致,对于仿函数和trait特性可以不用class,而是使用struct。
  • 注意:类和结构体的成员变量使用不同的命名规则。

###继承

使用组合(composition)常常比使用继承更合理。如果使用继承的话,定义为public继承。

定义:

  • 当子类继承基类时,子类包含了父基类所有数据及操作的定义。C++实践中,继承主要用于两种场合:实现继承(implementation inheritance),子类继承父类的实现代码;接口继承(interface inheritance),子类仅继承父类的方法名称。

优点:

  • 实现继承通过原封不动的服用基类代码,减少了代码量。由于继承实在编译时声明,程序员和编译器都可以理解相应操作并发现错误。从编程角度而言,接口继承时用来强制类输出特定的API。在类没有实现API中某个必须的方法时,编译器同样会发现并报告错误。

缺点:

  • 对于实现继承,由于子类的实现代码散步在父类和子类之间,要理解其实现变得更加困难。子类不能重写父类的非虚函数,当然也就不能修改器实现。基类也可能定义了一些数据成员,还要区分基类的实际布局。

结论:

  • 所有继承必须是public的,如果你想使用私有继承,你应该替换成把基类的实例作为成员对象的方式。
  • 不要过度使用实现继承。组合常常更合适一些。尽量做到只在“is a”情况下使用继承:如果Bar的确“是一种”Foo,Bar才能继承Foo。
  • 必要的话,析构函数声明为virtual。如果你的类有虚函数,则析构函数也应该为虚函数。注意数据成员在任何情况下都必须是私有的。
  • 当重载一个虚函数,在衍生类中把它明确的声明为virtual。理论依据:如果省略virtual关键字,代码阅读者不得不检查所有父类,以判断该函数是否是虚函数。

###多重继承

真正需要用到多重实现继承的情况少之又少。只有在以下情况下我们才允许多重继承:最多只有一个基类是非抽象类;其它类都是以Interface为后缀的纯接口类。

定义:

  • 多重继承允许子类拥有多个基类。要将作为纯接口的基类和具有实现的基类区分开来。

优点:

  • 相比单继承,多重实现继承可以复用更多的代码。

缺点:

  • 真正需要用到多重实现继承的情况少之又少。多重实现继承看上去是不错的解决方案。但你通常也可以找到一个更明确,更清晰的不同解决方案。

结论:

  • 只有当所有父类除第一个外都是纯接口时,才允许使用多重继承。为确保它们是纯接口,这些类必须以Interface为后缀。

关于该规则,Window下有个特例,请参见:Google的C++代码风格9:规则特例。

###接口

接口是指满足特定条件的类,这些类以Interface为后缀(不强制)。

定义:

  • 当一个类满足以下要求时,称之为纯接口:
    • 只有纯虚函数("=0")和静态函数(除了下文提到的析构函数)。
    • 没有非静态数据成员。
    • 没有定义任何构造函数。如果有,也不能带有参数,并且必须为protected。
    • 如果它是一个子类,也只能从满足上述条件兵役Interface为后缀的类继承。
  • 接口类不能为直接实例化,因为它声明了纯虚函数。为确保接口类的所有实现可悲正确销毁,必须为之声明虚析构函数(作为上述第一条规则的特例,析构函数不能是纯虚函数)。

优点:

  • 以Interface为后缀可以提醒其他人不要为该接口类增加函数实现或者非静态数据成员。这一点对于多重继承尤其重要。另外,对于Java程序员而言,接口的概念已经深入人心。

缺点:

  • Interface后缀增加了类名长度,为阅读和理解带来不便。同时,接口特性作为实现细节不应暴露给用户。

结论:

  • 只有在满足上述需求是时,类才以Interface结尾,但反过来,满足上述需要的类未必一定以Interface结尾。

###运算符重载

除少数特定环境外,不要重载运算符。

定义:

  • 一个类可以定义诸如+和/等运算符,使其可以像內建类型一样直接操作。

优点:

  • 使代码看上去更加直观,类表现的和內建类型(如int)行为一致。重载运算符使Equals(),Add()等函数名黯然失色。为了使一些模板函数正确工作,你可能必须定义操作符。

缺点:

  • 虽然操作符重载令代码更加直观,但也有一些不足之处:
    • 混淆视听,让你误以为一些耗时的操作和操作內建类型一样轻巧。
    • 更难定位重载运算符的调用点,查找Equals()显然比对应的==调用点要容易的多。
    • 有的运算符可以对指针进行操作,容易导致bug。Foo + 4做的是一件事情,而&Foo + 4可能做的是完全不同的另外一件事情。对于二者,编译器都不会报错,使其很难调试。
  • 重载还有令你吃惊的副作用。比如,重载了operator&的类不能被前置声明。

结论:

  • 一般不要重载运算符。尤其是赋值操作(operator=)比较诡异,应避免重载。如果需要的话,可以定义类似Equals(),CopyFrom()等函数。
  • 然而,极少数情况年可能需要重载运算符以便与模板或者“标准”C++类互操作(如operator<<(ostream&, const T&))。只有被证明是完全合理的才能重载,但你还是要尽可能避免这样做。尤其是不要仅仅为了在STL容器中用作键值就重载operator==或者operator<;相反,你应该在声明容器的时候,创建相等判断和大小比较的仿函数类型。
  • 有些STL算法确实需要重载operator==时,你可以这么做,记得别忘了在文档中说明原因。

###存取控制

将所有数据成员声明为private,并根据需要提供相应的存取函数。例如,某个名为foo_的变量,其取值函数时foo()。还可能需要一个赋值函数set_foo()。
特例是,静态常量数据成员(一般写作kFoo)不需要是私有成员。
一般在头文件中把存取函数定义成内联函数。
###声明顺序
在类中使用特定的声明顺序:public:在private:之前,成员函数在数据成员(变量)前。

类的访问控制区段的声明顺序依次为:pubic:,protected:,private:。如果某区段没有内容,可以不声明。

每个区段内的声明通常按以下顺序:

  • typedefs和枚举
  • 常量
  • 构造函数
  • 析构函数
  • 成员函数,含静态成员函数
  • 数据成员,含静态数据成员

友元声明应该放在private区段。如果用宏DISALLOW_COPY_AND_ASSIGN禁用拷贝和赋值,应当将其置于private区段的末尾,也即整个类声明的末尾。参见可拷贝类型和可移动类型。

.cc文件中函数的定义应尽可能和声明顺序一致。

不要在类定义中内联大型函数。通常,只有那些没有特别意义或者性能要求高,并且是比较短小的函数才能被定义为内联函数。

###编写简短函数

倾向于编写简短、凝练的函数。

我们承认长函数有时是合理的,因此并不硬性限制函数的长度。如果函数超过40行,可以思索一下能不能在不影响程序结构的前提下对其进行分割。
  即使一个长函数现在工作非常好,一旦有人对其修改,有可能出现新的问题,甚至导致难以发现的bug。使函数尽量简短,便于他人阅读和修改代码。
  在处理代码时,你可能会发现复杂的长函数。不要害怕修改现有代码:如果证实这些代码使用/调试困难,或者你需要使用其中的一小段代码,考虑将其分割为更加简短并且易于管理的若干函数。

###总结

  1. 不在构造函数中做太多逻辑相关的初始化。
  2. 编译器提供的默认构造函数不会对变量进行初始化,如果定义了其它构造函数,编译器不再提供,需要编码者自行提供默认构造函数。
  3. 为避免隐式转换,需将单参数构造函数声明为explicit。
  4. 为避免拷贝构造函数、赋值操作符的滥用和编译器自动生成,可将其声明为private且无需实现(也可以利用C++11的特性将其声明为=delete)。
  5. 仅在作为数据集合时使用struct。
  6. 组合>实现继承>接口继承>私有继承>,子类重载的虚函数也要声明virtual关键字,虽然编译器允许不这样做。
  7. 避免使用多重继承,使用时,除一个基类含有实现外,其它基类均为纯接口。
  8. 接口类类名以Interface为后缀,除提供带实现的虚析构函数,静态成员函数外,其它均为纯虚函数,不定义非静态数据成员,不提供构造函数,提供的话,请声明为protected。
  9. 为降低复杂性,尽量不重载操作符。模板、标准类中使用时提供文档说明。
  10. 存取函数一般内联在头文件中。
  11. 声明次序:public -> protected -> private。
  12. 函数体尽量短小,紧凑,功能单一。
LLC谐振变换器设计实战:从工作原理到参数设计与调试 开关电源设计是电力电子领域的核心技术,其核心目标在于提升效率与功率密度。为实现这一目标,软开关技术应运而生,它通过精心控制开关器件的电压与电流波形,使其在开通或关断瞬间实现零电压或零电流切换,从而从根本上降低开关损耗。LLC谐振变换器正是这一技术的杰出代表,它通过引入谐振网络,巧妙地实现了主开关管的零电压开关和次级整流管的零电流开关。这种拓扑结构在服务器电源、通信设备及高端显示驱动等要求高效率、高功率密度的应用场景中价值显著。本文将以半桥LLC为例,深入剖析其工作模态与增益特性,并系统阐述其参数设计、仿真验 阅读详情

相关推荐

新装Win10/Win11后VMware虚拟机连不上网?手把手教你排查‘网络信息不可用’(从服务检查到网段配置)

本文详细介绍了在Windows 10/11系统上安装VMware Workstation后虚拟机无法联网的排查方法。从检查VMware NAT Service、DHCP Service等关键服务状态,到重置虚拟网络编辑器配置,再到内核设备驱动问题解决,手把手教你解决‘网络信息不可用’问题。特别针对VMCI驱动故障提供了实用解决方案,帮助用户快速恢复虚拟机网络连接。

weixin_28736335的博客 770

Google C++ Style Guide 笔记

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33716941的博客 595

Ollama内网离线部署大模型实战:从模型文件到私有化服务

本文详细介绍了如何在内网离线环境下,利用Ollama部署私有化大模型服务。内容涵盖从获取GGUF格式模型文件、手动安装Ollama、编写核心Modelfile配置文件,到创建运行模型、性能调优及安全加固的全流程实战指南,旨在帮助企业安全、可控地构建内部AI能力。

weixin_29209805的博客 214

C++ 风格指南

C++ 风格指南

zhaominyong的专栏 1044

VTK实战笔记(1)在win11搭建VTK-9.4.2 + qt5.15.2 + VS2019_x64开发环境

Visual Studio 2019 + qt5.15.2 + vtk9.4.2

心向阳光,斗志昂扬! 974

[Adaptive Autosar]深入理解--Time Synchronization

目录 1.TS典型应用场景 2.CP和AP时间同步对比 3.时间同步基础知识 4.TBR部分参数说明 5. TS功能说明 5.1 基本说明 5.2 时间纠正计算说明 5.3 时间验证 Time Synchronization 时间同步,后面简称TS 1.TS典型应用场景 时间同步,典型应用就是在自动驾驶领域,自动驾驶领域涉及到各个传感器的数据采集,如IMU采集当前车身姿态和运动信息,毫米波雷达-超声波雷达-环视摄像头-前视摄像头...等等传感器捕获的数据,在算法中需要精确知道每个数.

AgingMoon的博客 3997

Google C++ Style文档及常用代码规范(三):来自 Google 的奇技、其他 C++ 特性、规则特例、结束语

风格指南的重点在于提供一个通用的编程规范, 这样大家可以把精力集中在实现内容而不是表现形式上. 我们展示的是一个总体的的风格规范, 但局部风格也很重要, 如果你在一个文件中新加的代码和原有代码风格相去甚远, 这就破坏了文件本身的整体美观, 也让打乱读者在阅读代码时的节奏, 所以要尽量避免.不是标准 C++ 的组成部分. 更重要的是, 它们根据数据大小动态分配堆栈内存, 会引起难以发现的内存越界 bugs: “在我的机器上运行的好好的, 发布后却莫名其妙的挂掉了”.所以拿不准时,干脆用更大的类型。

MAVER1CK的博客 1299

法兰克仿真软件FANUC CNC Guide v25.0 安装教程及中文设置

下载地址在文末。我们公司用新到一批FANUC 系统的设备,为方便使用就装了一个 FANUC 数控系统仿真软件FANUC CNC Guide v25.0 ,还是最新版不是市面上流传的老版本。模拟学习一下。

hakesashou的博客 1万+

Google C++ 开源风格指南

Google 在 C++ 编程中的代码风格规范、命名约定、注释要求和格式规定,提升代码的可读性、可维护性和规范性。

有耐心做好简单事情,坚持写blog 4192

保姆级教程:用CANoe手把手复现ECU刷写全流程(含BootLoader三阶段详解)

本文提供了一份详细的CANoe ECU刷写实战指南,涵盖BootLoader三阶段的深度解析。从实验环境搭建到预编程、主编程及后编程阶段,逐步讲解ECU刷写的关键步骤和隐藏逻辑,特别强调UDS诊断和CAN通信的精确控制,帮助开发者掌握ECU刷写的核心技术。

weixin_29234423的博客 528

2025-03-21(DS复习): Databricks 的技术架构

Databricks 的技术架构以 ​为核心,构建了一套高度集成、可扩展且支持多云环境的统一分析平台。其架构设计注重存储与计算的深度融合,并通过丰富的服务层功能简化了数据工程、机器学习和数据科学的工作流。

baidu_24377669的博客 1428

Google C++ Style Guide - Google C++ 风格指南

Google C++ Style Guide - Google C++ 风格指南

程永强 2312

【STK】手把手教你利用STK进行进行光电红外仿真02-STK/EOIR模块属性之一 传感器选项设置

EOIR传感器可以从空间几何属性、光谱属性、光学属性、辐射属性四个方面进行设置,并且可以设置信号传播路径中的大气特性,包括大气模型、气溶胶模型、气象学可见性和大气湿度。在定义EOIR传感器时,需要Sensor——Definition属性页中,将Sensor Type设置为EOIR。单击下面的按钮打开传感器的EOIR配置页,可以对传感器的属性进行配置,此外,还可以在场景中视情况添加相关的中心体。路径辐射损耗影响上述特性的计算,计算的结果考虑了传感器、目标位置的影响,但是还没考虑地球临边背景的影响。

weixin_44184852的博客 3199

C++ Google代码风格

C++ Google代码风格0 index(扉页)0.0 声明0.1 译者前言0.2 背景headers(头文件)1.1 Self-contained 头文件1.2. #define 保护1.3. 前置声明1.4. 内联函数1.5. #include 的路径及顺序译者(acgtyrant)笔记scoping(作用域)2. 作用域2.1. 命名空间2.2. 匿名命名空间和静态变量2.3. 非成员函数...

baidu_28926495的博客 1623

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

BAML C++ SDK 代码风格指南:Google 布局与标准库命名的工程实践

本文以 [baml_language/sdks/cpp/STYLE.md](https://link.gitcode.com/i/51b97241bd9f795a24c743a694047dac) 为骨架,系统讲解 BAML C++ SDK 的代码风格约定:布局(Layout)采用 Google 风格,命名(Naming)遵循 C++ 标准库的下划线风格,以及这套约定背后的源码级实现与例外条款。读

gitblog_00688的博客 389

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

google代码风格(C++)

from    http://code.google.com/p/google-styleguide/   版本:   3.133 原作者: Benjy Weinberger Craig Silverstein Gregory Eitzmann Mark Mentovai Tashana Landray 翻译: YuleFox yospaly 项目主页:

昨天的你 4010

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain&#39;s apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath(&#39;DeepLearnToolbox&#39;));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand(&#39;state&#39;,0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W&#39;); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand(&#39;state&#39;,0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = &#39;sigm&#39;;%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, &#39;Too big error&#39;);```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand(&#39;state&#39;,0)sae = saesetup([784 100]);sae.ae{1}.activation_function = &#39;sigm&#39;;sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)&#39;)% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = &#39;sigm&#39;;nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, &#39;Too big error&#39;);```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x&#39;,28,28,60000))/255;test_x = double(reshape(test_x&#39;,28,28,10000))/255;train_y = double(train_y&#39;);test_y = double(test_y&#39;);%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you&#39;ll get around 1.2% errorrand(&#39;state&#39;,0)cnn.layers = { struct(&#39;type&#39;, &#39;i&#39;) %input layer struct(&#39;type&#39;, &#39;c&#39;, &#39;outputmaps&#39;, 6, &#39;kernelsize&#39;, 5) %convolution layer struct(&#39;type&#39;, &#39;s&#39;, &#39;scale&#39;, 2) %sub sampling layer struct(&#39;type&#39;, &#39;c&#39;, &#39;outputmaps&#39;, 12, &#39;kernelsize&#39;, 5) %convolution layer struct(&#39;type&#39;, &#39;s&#39;, &#39;scale&#39;, 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, &#39;Too big error&#39;);```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand(&#39;state&#39;,0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, &#39;Too big error&#39;);%% ex2 neural net with L2 weight decayrand(&#39;state&#39;,0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, &#39;Too big error&#39;);%% ex3 neural net with dropoutrand(&#39;state&#39;,0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, &#39;Too big error&#39;);%% ex4 neural net with sigmoid activation functionrand(&#39;state&#39;,0)nn = nnsetup([784 100 10]);nn.activation_function = &#39;sigm&#39;; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, &#39;Too big error&#39;);%% ex5 plotting functionalityrand(&#39;state&#39;,0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = &#39;softmax&#39;; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, &#39;Too big error&#39;);%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand(&#39;state&#39;,0)nn = nnsetup([784 20 10]); nn.output = &#39;softmax&#39;; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, &#39;Too big error&#39;);```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Abseil代码风格指南:Google C++代码规范的实践

在现代软件开发中,代码风格一致性是保证项目可维护性和可读性的关键因素。Google的C++代码规范被业界广泛认可,而Abseil库正是这一规范的完美实践。作为Google内部C++代码库的开源版本,Abseil不仅提供了高质量的C++组件,更展示了如何在实际项目中应用Google的代码风格规范。 本文将深入解析Abseil代码库中的风格实践,帮助开发者理解和应用这些最佳实践。 ## 命名约定:...

gitblog_00685的博客 984

LevelDB设计模式:Google C++代码风格深度解析 [特殊字符]

LevelDB是Google开发的一个高性能键值存储库,采用Google C++代码风格构建。这个开源项目展示了Google内部代码标准的最佳实践,为C++开发者提供了极好的学习范例。本文将深入解析LevelDB的设计模式和代码风格特点。 ## Google C++代码风格的核心原则 LevelDB严格遵循[Google C++代码风格指南](https://google.github.io/

gitblog_00077的博客 1093

终极指南:掌握Google C++代码风格规范的10个核心技巧

Google C++代码风格规范是业界公认的C++编程标准,为开发者提供了一套完整的代码编写指南。作为C++程序员,遵循这套规范不仅能提升代码质量,还能让团队协作更加顺畅。本文将通过10个关键技巧,带你从规范到实践全面掌握Google C++代码风格。🚀 ## 📝 为什么需要代码风格规范? 在大型项目开发中,统一的代码风格至关重要。Google C++规范强调**可读性优先**、**一致性

gitblog_00338的博客 409

Google的C++编程规范总结

文章目录引言1 格式1.1 每行代码不多于 80 个字符1.2 使用空格(Space),而不是制表符(Tab)来缩进,每次缩进4个字符1.3 指针符号*,引用符号& 的位置,写在靠近类型的地方1.4 花括号位置1.5 if, for, while等语句就算只有一行,也强制使用花括号2 命名约定2.1 使用英文单词,不能夹着拼音2.2 总体上采用骆驼命名法2.3 名字不要加类型前缀2.4 类...

蒋成的博客 5262

Google C++编程风格指南

  [译]Google C++编程风格指南(八)[完] 2008年09月03日 星期三 17:06 原文地址:Google C++ Style Guide 规则之例外前面说明的编码习惯基本是强制性的,但所有优秀的规则都允许例外。1. 现有不统一代码(Existing Non-conformant 阅读全文>> 类别:c

skyremember的专栏 1234

一张图总结Google C++编程规范(Google C++ Style Guide)

Google C++ Style Guide是一份不错的C++编码指南,我制作了一张比较全面的说明图,可以在短时间内快速掌握规范的重点内容。不过规范毕竟是人定的,记得活学活用。看图前别忘了阅读下面两条重要建议: 1 保持一致也非常重要,如果你在一个文件中新加的代码和原有代码风格相去甚远的话,这就破坏了文件本身的整体美观也影响阅读,所以要尽量避免。 2 一些条目往往有例外,比如下面这些,所以本图不能代替文档,有时间还是把PDF认真阅读一遍吧。

voidccc的专栏 5万+

《GOOGLE C++ 编程规范》读书笔记

GOOGLE C++ 规范读书笔记 1、头文件 1、使用#define避免头文件被重复包含,定义的宏为全路径+文件名; 2、能使用前置声明的地方尽量不使用#include。即如果不需要访问类定义的情况下,使用类的前置声明即可;需要类定义时,则必须得包含头文件。 3、只有当函数只有10行甚至更少时才将其定义为内联函数;内联包含循环或switch语句的函数常常是得不尝失(除非在大多数情况下

pointersky的专栏 989

向google学习良好的C++代码风格-(1)概述

第2学堂-专栏 3510

[C++] 编程实践之1: Google的C++代码风格4:来自Google的奇技

来自Google的奇技  Google用了很多自己实现的技巧/工具使C++代码更加简装,我们使用C++的方式可能和你在气他地方见到的有所不同。所有权与智能指针 动态分配出的对象最好有单一且固定的所有主(owner),且通过智能指针传递所有权(ownership)。 定义: 所有权是一种登记/管理动态内存和其它资源的技术。动态分配出的对象的所有主是一个对象或者函数,后者负责确保当前者无用时就自动销

魔豆(Magicbean)的博客 628

Google C++编程风格指南:cpplint报错信息解决汇总

Google C++编程风格指南:cpplint报错信息解决汇总

LF__plus的博客 2601
上一篇: [C++] 编程实践之1: Google的C++代码风格2:作用域
下一篇: [C++] 编程实践之1: Google的C++代码风格4:来自Google的奇技
魔豆Magicbean
博客等级 码龄19年 146粉丝 742原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值