Effective C++告诉我的那些事(一)

1 篇文章 0 订阅

c++语言和C语言的区别

  • C语言
    C++说到底还是以C语言为基础的。
  • Object-Oriented C++
    我更愿意称为面向对象的守则,包含了C所没有的一些特性,class、封装、继承、多态、虚函数等等一系列。
  • Template C++
    泛型编程的部分,确实很强大,不过以我现在的水准好像用的地方就只有代码的复用,可变参数和一些精彩的推演我目前是,只见过猪跑,还吃不到猪肉。比如move、forward、函数对象的底层实现,确实很厉害尤其是functiona。
  • STL
    C++选手必备的一个template程序库,使用起来很方便,面试起来就不那么容易了,想深入还是有不少东西。不知道有没有必要研究一下侯捷的STL,等有空吧。

尽量用const,enum,inline替换#define

  • #define不是语言的一部分,比如tmp在预编译就被移走了,不会进到记号表,当获得一个编译错误时,编译器只会报出1.666,尤其是这个定义式在其他文件时,这就太难定位错误了。用const替换会进入到记号表。而且const省内存,只会有一块内存。
#define tmp 1.666;

const double tmp = 1.666;
  • #define是没有作用域的
    如果想要限制某个变量于类内,只能使用const,那么const变量是每个对象都有的,且对于每个对象来说是不可修改的,即不可赋值,所以只能在初始化列表进行初始化,不能在{}里进行赋值。

static const

static 保证变量为类作用域,对象共享,即变量是唯一一份
const保证变量不被修改
static const 保证变量唯一且不被修改

class test
{
private:
	static const int size = 100;
	//const int size;  这样会报错    //记住const变量一定要在初始化列表初始化,不能赋值
	int arr[size];
};
const int test::size;   //这不是必须的

这就是应用场景,应该用的不多吧?至于为什么呢?如果不加static,主要有2点:
1.数组要在编译期确定大小,const int size ; 只能在运行期对象初始时确定size的值,违背了C++逻辑。
2.数组确定大小,要保证大小唯一,const int size;每个对象都有一个size,编译器无法确定大小。
但是如果使用了static,在编译器键可以确定size的值,而且是唯一的,所有对象共享一份,完美解决问题。
问题:const成员变量要在初始化列表初始化,static要在类外写定义式,so?
1.如果这个变量只是使用值,那么直接在类内定义即可
2.如果要取变量的地址,则必须在类外定义,但不用给予值,因为类内可以给。

  • enum有什么用
    我基本没怎么用过,muduo里倒是见过,可能还是太菜。
class test
{
private:
	enum {size = 100};
	int arr[size];
};

取一个枚举的地址是不合法的。 所以大概是不想让别人用一个指针或者引用指向我的变量,用enum确实可以实现。

  • #define最大的坑
    宏函数是比较坑的,小括号一定要上好,但是下面是比较隐式的错误。
#define num_max(a,b)  f((a) > (b) ? (a):(b))

int a = 5, b = 0;
num_max(++a,b);      //a被加了2次
num_max(++a,b+10);   //1次

坑爹,比较的过程,和返回时都被++,#define不遵守作用域和访问规则。
下面这样就可以,bunSum是一个真正的函数。

template<typename T>
inline void numSum(const T& a,const T& b)
{
	f(a > b ? a : b);
}

使用const

  1. const与一级指针结合有2种方式,与二级指针有3种。
const int* p = nullptr;
int* const p = nullptr;

但是迭代器有点颠覆我的认知,比较特殊

const std::vector<int>::iterator it = vec.begin();  //相当于T* const
std::vector<int>::const_iterator it = vec.begin();  //相当于 const T*
  1. 2个函数,只是因为常量属性不同,是可以构成重载的。
  2. const与non-const函数
    const -> non-const no
    non-const -> const ok

为什么?我觉得从逻辑就能想明白。
如果非要调用也不是没办法

消除掉const, 变成non-const -> non->const

同时,如果const与non-const的实现等价的话,可以用non-const -> const,但是参数要是const的话,可以用static_cast添加const属性

const_cast<test&>(*this)       //消除常量属性
//消除掉const,    变成non-const  ->  non->const
static_cast<const test&>(*this)
//同时,如果const与non-const的实现等价的话,可以用non-const  -> const,但是参数要是const的话,可以用static_cast添加const属性

对象初始化的顺序

  1. 确定对象在使用前被初始化
    关于对象安全,陈硕讲的主要是多线程下对象的使用与释放的安全。和这里结合貌似就完整了。
    使用未初始的对象,会发生不可预知的错误。

  2. 初始化列表的作用 初始化/赋值
    初始化列表是初始化
    构造函数的{}是赋值,也就是说会进行2步。
    对象的初始化时进入到构造函数本体之前的。**对于const与引用,是只能初始化,而不能进行赋值的,**所以尽量使用初始化列表吧,总没错。

  3. 对象初始化的顺序
    这个应该算是一个C渣渣必备的知识。
    1.基类先于派生类构造
    2.成员变量按声明顺序初始化,与其他顺序无关
    3.全局对象是先于main函数初始化的,全局对象之间依旧执行条款2
    4.补充2:如果一个变量arr依赖于另一个变量a,a先初始化

  4. 跨文件的对象安全
    防止使用对象时,对象还未初始化。可以使用函数调用而不是使用对象。
    这个函数主要作用是可以生成一个static对象,然后返回引用,有点类似于单例模式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值