Effective C++ (01)

条款1:

C++:

         c、面向对象的c++、带模版的c++、STL 

条款2:尽量以const、enum、inline代替#define

宁可以编译器替换预处理器。#define没有进入符号表,造成无法跟踪。

常量指针。

以const代替#define的所谓常量定义功能

以inline代替#define的所谓宏定义功能

class内部的专属常量。为了将常量的作用域限制于class内,必须让其成为一个类的成员,为了确保这个常量只有一份,必须声明为static。


const int GamePlayer::m_nNumTurns;Class GamePlayer
{
    Static const int m_nNumTurns = 5;
    Int scores[m_nNumTurns];
};
 
const int GamePlayer::m_nNumTurns;

C++通常需要一个定义式,然而如果是class专属常量又是static且为整数类型(int、char、bool),则需要特殊处理。只要不取它们的地址,可以声明并使用它们而无需提供定义式。但如果要取class常量的地址,就必须提供一个定义式:

要放入实现文件而非头文件,由于在声明时已经获得初值,因此定义时不可以在设初值。

声明是原形,定义时具体实现。。。

enum hack:

一个枚举类型的数值可以充当int被使用。

Class GamePlayer
{
    enum{m_nNumTurns = 5};
    Intscores[m_nNumTurns];
};


取一个enum的地址不合法,取一个#define也不合法。

如果不想让别人获得一个pointer或reference,enum可以实现。

宏定义:副作用。

用template inline代替宏定义。

 

条款3:尽可能使用const

const出现在*的左边,表示被指物是常量;如果出现在*右边,表示指针本身是常量;如果出现在*两边,则两者都是常量。

const int widget = 1;

int const widget = 1; 

STL的迭代器是以指针为基础的,迭代器的作用类似于T*指针。声明iterator为const就像声明指针为const一样(T* const)。表示这个迭代器不能指向其他不同的东西,但它指向的东西的值是可以变的。

如果希望它所指向的值是不能改变的,需要const_iterator(const T*)

std::vector<int> vec;
const std::vector<int>::iterator iter= vec.begin();
*itr = 10;  //没有问题
++itr;        //错误!常量指针不能再指向其他的地方
std::vector<int>::const_iterator itr= vec.begin();
*itr = 10; // 错误!
++itr;        //没有问题
  函数返回值为const:

有理数的operator*声明

class Rational {…};

const Rational operator* (constRational& lhs, const Rational& rhs);

可以避免下述操作:

Rational a,b,c;

(a*b) = c;

在operator*的结果上再调用operator=。

例如if (a * b = c) // 可能是==

如果是内置类型,直接不合法。因此一个设计良好的用户自定义类型,需要与内置类型无缝对接好。

参数为const:

除非要对参数进行修改并返回,否则尽量声明为const

const成员函数

目的:为了确认该成员函数能够作用于const对象上面。

1:使class接口比较容易被理解。得知哪个函数可以改动对象而哪个不行,加了const的函数一目了然。

2:使操作const对象成为可能。这对高效编程很有效。改善c++性能的一个方法是由传值调用改为传引用,而前提是有const成员函数可以用来处理const对象。

         问题:非const成员函数不能处理const对象???

如果成员两个函数的const性质不同,则可以被重载!

Class TextBlock
{
    Const char& operator[](std::size_t position) const // const对象的
{
    Ruturn text[position];
}
Char& operator[](std::size_t position) // 非const对象的
{
    Return text[position];
}
Private:
    Std::string text;
};
 
Textblock tb(“Hello”);
Cout << tb[0]; // 调用非const对象的
Const TextBlock ctb(“World”);
Cout << ctb[0]; // 调用const对象的
真实中:const对象大多用于函数调用的传递结果。

例如:

Void Print(const TextBlock& cbt)
{
    Cout << ctb[0];
}

只要重载,给予不同版本不同的返回值。

如何在const成员函数内部修改成员数据的值?mutable。 

Class TextBlock
{
Const char& operator[](std::size_t position) const // const对象的
{
    Length = XXX;
    Ruturn text[position];
}
Char& operator[](std::size_t position) // 非const对象的
{
    Return text[position];
}
Private:
Std::string text;
Mutable int length;
};
 

如果const和非const的代码有大量重复,则可以用非const的代码调用const的代码 

Class TextBlock
{
Const char& operator[](std::size_t position) const // const对象的
{
    Ruturn text[position];
}
Char& operator[](std::size_t position) // 非const对象的
{
    // 先将非const对象将其转化为const类型,const返回const char&类型,再将其去掉const性质,转化为char&类型、
    // 如果不转化为const对象,则会调用自己,无限循环。。。
    Return const_cast<char&> (static_cast<const TextBlock&>(*this) [position]);
}
Private:
Std::string text;
};

条款4:确定对象在使用前已被初始化

int x;

int arr[10];

数组不保证被初始化,内容是随机的

int arr[10] = {0}; 

当x是成员函数时,不保证被初始化为0.初始化是程序员的事。

初始化与赋值的区别。类内的成员对象的初始化在初始化列表中完成,即在程序员提供的显式构造函数之前,在程序员提供的显式代码里,被初始化后的内置对象将执行operator=(赋值)操作。

对于类内的内置数据类型(int、char),编译器在成员初始化列表内不管它们,由程序员负责。

当想让初始化列表调用对象的默认构造函数时,可以:theObj()。编译器会自动给你调用对象的默认构造函数。但是尽量将所有的成员都在初始化列表中出现!以避免遗漏内置类型

如果是const、reference则必须在初始化列表中初始化!因为const、reference只能被初始化一次,如果没有在初始化列表中提供,则编译器会默认给其初始化,而程序员则不能再显式的更改它们!

初始化次序:父类(按照继承顺序)、成员对象(按照声明顺序)。即使在初始化列表中顺序被打乱,也无影响。

所谓static对象,其寿命从被构造出来直到程序结束为止,因此stack和heap-based对象都被排除。

static的对象:定义于global的、定义于namespace的、在classes内的对象,这些对象没有static关键字。在函数内、在file作用域内声明为static的对象。在函数内声明为static的对象为局部对象,其他的都是non-local static。它们的析构函数在main结束后自动调用。

函数内的static对象称为local static对象(因为它们对函数而言是local)

non-local static:定义于global的、定义于namespace的、在classes内的对象、file作用域内声明的static对象

如果一个非局部的static对象的初始化用到了另一个编译单元的某个非局部的static对象,而这个对象可能尚未被初始化!对于多个目标文件(编译单元)的非局部static的初始化次序没有定义。


class FileSystem{
pubic:
         size_tnumDisk() const;
};
extern FileSystem tfs;
 
class directory {
pubic:
         Directory(params);
};
Directory::Directory(params)
{
         size_tdisks = tfs.numDisks();
}

假设创建一个Directory对象:

Directory tempDir(params);

这里需要保证tfs在tempDir之前被初始化。但是它们定义于不同编译单元的非局部static对象。如何能保证tfs在tempDir之前先被初始化?

无法决定它们的初始化次序

extern : global对象 

将每一个非局部static对象搬到自己的专属函数内(对象被声明为static),函数返回一个指向它的引用,类似于单例模式?

C++保证,局部static对象会在该函数被首次调用期间被初始化 


class FileSystem{
pubic:
         size_tnumDisk() const;
};
FileSystem& tfs()
{
         staticFileSystem fs;
         returnfs;
}
 
class directory {
pubic:
         Directory(params);
};
Directory::Directory(params)
{
         size_tdisks = tfs.numDisks();
}
Directory& tempDir()
{
static Directorytd;
return td;
}

多线程下带有不稳定性

记住:

为内置对象(int char bool)手工初始化

构造函数最好使用初始化列表


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值