建立音乐网站优化网站结构一般包括
说明:部分涉及C++较高级功能的条款,如智能指针、并行编程等暂不研读,后续用到这部分再说,涉及这部分的条款仅标注并跳过不研究
1. 条款01
2. 条款02–尽量以const、enum、inline替换 #define
- 对于单纯常量,最好以const对象或者enums替换#define;
- 对于形似函数的宏,最好改用inline函数替换#define;
3. 条款03–尽可能使用const
- const对指针变量
char p1[]="Hello";
char* p2=p1;
const char* p= p2;//不可以通过*p改变所指向的变量的值
char const* p_=p2;//作用与上述相同。
char* const p3=p2;//p3不可以再改变其内存储的地址的值,地址所指向的内容可以改变,即可以通过*p3改变指向的内存的值。
const char* const p4=p2;//结合上述两者
- const函数
- 这部分没看懂,后续再补充
4. 条款04–确定对象在使用前已被初始化
- 如题所示,不管指针还是常量都需要初始化!
5. 条款05–了解C++默默编写并调用哪些函数
- C++会默认给class生成构造函数,析构函数,拷贝赋值,拷贝构造函数。
6. 条款06–若不想使用编译器自动生成的函数,就该明确拒绝
- 对于某种情况:如房产中介,一个中介软件是不希望某一个房子的类可以被复制,因为每个房子的信息都是独一无二的,因为为了防止这种情况,不仅自己不要定义拷贝构造和拷贝赋值函数,也要禁止编译器自动生成拷贝构造和拷贝赋值!!!。
class HomeForSale{...};
...
HomeForSale h1;
HomeForSale h2;
//希望以下两个操作被禁止
HomeForSale h3(h2);
h1=h2;
- 方法就是:自己主动声明拷贝构造和拷贝赋值函数,但是不予定义!并且把该二函数定义为private类型。注意只声明,不定义,这样防止类内函数调用该二函数。
- 方法一:将该类的拷贝构造和拷贝赋值声明为private,并且只声明,不定义。
class HomeForSale{
public:...
private:
//以下两个函数只声明,不定义。HomeForSale(const HomeForSale);HomeForSale& operator=(const HomeForSale);
};
- 方法二:定义uncopyable基类,然后令子类private继承。
class Uncopyable{
protected:Uncopyable(){}~Uncopyable(){}
private:Uncopyable(const Uncopyable&);Uncopyable& operator=(const Uncopyable&);
};
//只需要继承该类,就可以实现组织对象被拷贝
//子类不再需要声明拷贝构造函数和拷贝赋值函数
class HomeForSale:private Uncopyable
{...};
7. 条款07–为多态基类声明virtual析构函数
- 在动态绑定过程中(即利用基类指针指向子类),如果利用
new
新建一个指向子类的基类时,delete
该指针时,若基类的析构函数不是虚函数,则delete
只会对基类的析构函数操作,不会删除子类的内容,这就会造成内存泄漏。这片内存只有在程序结束时才会被系统回收。 - 概念:定义为虚函数不代表该函数不被实现,而是为了允许基类的指针可以调用子类的该函数; 定义一个函数为纯虚函数,代表该函数没有实现,只是为了实现一个接口,起到一个规范的作用,规范继承这个类的子类必须实现该函数
class father
{father();vitrual ~father();
};
father::father(){}
father::~father(){cout<<"delete father"<<endl;}class son:public father
{son(){}~son(){cout<<"delete son"<<endl;}string name;
};
int main()
{father* test=new son();delete test;return 0;
}
/*
输出结构:
delete son
delete father
若没有加virual,则只输出:
delete father
*/
8. 条款08–别让异常逃离析构函数
- 析构函数绝对不要抛出异常,这在数组或者STL操作析构时,系统对同时抛出的多个异常会导致不明确行为。因此如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉异常,然后吞下它们或者直接结束程序,不造成不必要的崩溃;
- 如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数执行该操作
9. 条款09–绝不在构造和析构过程中调用virtual函数
- 在构造和析构期间不要调用virtual函数,因为这类调用从不下降至derived class
10. 条款10–令operator=返回一个reference to *this
- 令赋值操作返回reference to *this,这是标准库提供的类型里都以这样的形式返回,所以作者建议“从众”
Widget& operator=(const Widget& rhs)
{...return *this;
}
- 该操作也适用
+=
,-=
,*=
等赋值运算
Widget& operator+=(const Widget& rhs)
{...return *this;
}
Widget& operator-=(const Widget& rhs)
{...return *this;
}
Widget& operator*=(const Widget& rhs)
{...return *this;
}
11. 条款11–在operator=中处理“自我赋值”
- 如题目所示,用户会出现自己对自己赋值的情况,尤其是对含指针的类的操作。
- 假设类中定义了一个指针变量,并利用动态分配为其分配了内存,赋值operator的一般定义如下(含有潜在危险)
class Widget{double* tt;Widget(){tt=new double();}Widget& operator=(const Widget& rhs){delete tt;//先把tt原先指向的内容删除tt=new double(*rhs.tt);//为tt申请新的内存,并指向右端项的值return *this;}
};
- 优化一:
Widget& operator=(const Widget& rhs)
{if(this==&rhs) return *this;delete tt;tt=new double(*rhs.tt);return *this;
}
- 优化二:
Widget& operator=(const Widget& rhs)
{double* mm=tt;tt=new double(*rhs.tt);delete tt;return *this;
}
- 还有其他优化方法,这里暂不总结。
12. 条款12–复制对象时勿忘每一个成分
- 总结就是对于继承的子类,在处理
=
的操作符时,不要忘记对其继承的基类里的变量也进行复制。 - 并且拷贝构造和拷贝赋值不能混用,具体书写格式如下
class Child::public Father
{
//拷贝构造
Child(const Child &rhs):Father(rhs),num(rhs.num){}
Child(){}
double num;
//拷贝赋值
Child& operator=(const Child& rhs)
{Father::operator=(rhs);num=rhs.num;return *this;
}
};
13. 条款13–以对象管理资源
14. 条款14–在资源管理类中小心copying行为
15. 条款15–在资源管理类中提供对原始资源的访问
16. 条款16–成对使用new和delete
//即对于数组的new出来的新指针,delete要加中括号
double test=new double[4];
delete[] test;
17. 条款17–以独立语句将newed对象置入智能指针
- 跳过