第一章 习惯C++

C多出来的部分
一、语言联邦

    1、c
    2、面向对象C++
    3、Template C++ 
    4、STL

二、const,enum,inline替换#define

1、预处理都做了什么?
整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换
2、static的作用
3、inline函数的作用

!!!inline关键字放在函数返回类型前,函数实现处必须写inline关键字
一般来说,调用一个函数流程为:当前调用命令的地址被保存下来,程序流跳转到所调用的函数并执行该函数,最后跳转回之前所保存的命令地址。

对于需要经常调用的小函数来说,这大大降低了程序运行效率。所以,C99 新增了内联函数(inline function)。

关键字 inline 告诉编译器,任何地方只要调用内联函数,就直接把该函数的机器码插入到调用它的地方。这样程序执行更有效率,就好像将内联函数中的语句直接插入到了源代码文件中需要调用该函数的地方一样。

要将一个函数定义为内联函数,需要在函数定义时加上 inline 函数修饰符。

避免了频繁调用函数对栈内存重复开辟所带来的消耗。 inline有更强的约束性和能够让编译器检查出更多错误的特性,这是宏所不具备的

在c/c++中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了inline修饰符,表示为内联函数。

栈空间就是指放置程序的局部数据(也就是函数内数据)的内存空间。在系统下,栈空间是有限的,假如频繁大量的使用就会造成因栈空间不足而导致程序出错的问题,如,函数的死循环递归调用的最终结果就是导致栈内存空间枯竭。
#include <stdio.h>
//函数定义为inline即:内联函数

inline char* dbtest(int a) {
    return (i % 2 > 0) ? "奇" : "偶";
} 

int main()
{
   int i = 0;
   for (i=1; i < 100; i++) {
       printf("i:%d    奇偶性:%s /n", i, dbtest(i));    
   }
}

2. inline使用限制
inline的使用是有所限制的,inline只适合涵数体内代码简单的涵数使用,不能包含复杂的结构控制语句例如while、switch,
并且不能内联函数本身不能是直接递归函数(即,自己内部还调用自己的函数)

慎用inline
内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。 

如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。另一方面,
每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。
以下情况不宜使用内联: 
(1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。 
(2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。
https://www.cnblogs.com/fnlingnzb-learner/p/6423917.html

总结一下,
对于单纯常量,最好以const 对象或者enum替换#define
对于形似函数的宏,最好用inline函数替换#define

三、尽可能得使用const
1、常量指针和指针常量的区别 一个修饰的指针,一个修饰的是值,修饰谁,谁不能被修改
识别方法:const在星号左边,表示被指的物是常量,如果出现在星号右边,表示指针自身是常量
<1> 常量指针
指针指向的对象是常量,那么这个对象不能被更改。
在C/C++中,常量指针是这样声明的:

1)const int *p;

2)int const *p;

<2>指针常量

指针是形容词,常量是名词。这回是以常量为中心的一个偏正结构短语。那么,指针常量的本质是一个常量,
而用指针修饰它,那么说明这个常量的值应该是一个指针。

指针常量的值是指针,这个值因为是常量,所以不能被赋值。

在C/C++中,指针常量这样声明:

int a;

int *const b = &a; 

//const放在指针声明操作符的右侧

2、const在函数前面或者后面
<1>、const在函数的前面,这种用法,是在修饰函数的返回值
例如函数
constchar * GetString(void);
如下语句将出现编译错误:
char*str = GetString();

正确的用法是
constchar *str =GetString();
如果函数返回值采用“值传递方式”,由于函数会把返回值复制到外部临时的存储单元中,加const修饰没有任何价值。
例如不要把函数intGetInt(void) 写成constint GetInt(void)。
同理不要把函数AGetA(void) 写成constA GetA(void),其中A为用户自定义的数据类型。
如果返回值不是内部数据类型,将函数AGetA(void) 改写为constA &GetA(void)的确能提高效率。但此时千万千万要小心,一定要搞清楚函数究竟是想返回一个对象的“拷贝”还是仅返回“别名”就可以了,否则程序会出错。
函数返回值采用“引用传递”的场合并不多,这种方式一般只出现在类的赋值函数中,目的是为了实现链式表达。

<2>、const在函数后面,叫const成员函数

const成员函数的特点,不慎修改了数据成员,或者调用了其它非const成员函数,编译器将指出错误


四、确定对象初始化
    1、区别好赋值和初始化
    <1>、C++规定,对象成员变量的初始化动作发生在进入构造函数本体之前
    <2>、如果有多个构造函数,多份成员初始化列可能会觉得无聊,这个时候可以选择性的
将重复部分,封装为函数,进行赋值
    <3>、成员初始化顺序,和成员变量声明次数初始化,这个和它们成员初始化列
中的顺序无关
 

#pragma once
#include <string>

class Initialize
{
public:
    Initialize(const char* pszName,int iSecond);

    ~Initialize();

private:

    std::string m_strName;
    std::string m_strPwd;

    int m_iSecond;
};

#include "Initialize.h"

Initialize::Initialize(const char* pszName, int iSecond): m_strName(""), m_iSecond(0) // 初始化
{
    m_strPwd = "";// 赋值操作,调用了类的构造函数
}

Initialize::~Initialize()
{

}

2、需要特殊考虑的需要初始化的
    理解下 non-local static 对象
    函数内的static对象成为local static 对象,其他static对象成为 non-local static对象
本章忠告:
1、为内置型对象进行手工初始化,因为C++不保证初始化他们
2、构造函数最后使用成员初始列,而不要再构造函数中使用赋值操作
    注意初始化顺序和成员在class中的声明次序相同
3、为免除"跨编译单元之初始化次序"问题,请用local static 对象替换non-local static对象   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值