1. C++编程简介
学习目标:培养面向对象的观念,能写出正规的、大气的代码。
1.1 C++分类
Object Base 基于对象
C++ with pointer : String
C++ without pointer : ComplexObject Oriented 面向对象
继承
委托等
1.2 C++ 发展
C -> new C -> C with class -> C++
c++98 (1.0)
c++11(2.0)
2. 头文件与类的声明
2.1 C 与C++的比较
C 将 data 与 function 分开, 因此, 函数(funciton)可以被任意一个数据调用,因此,data是全局的。C的代码超过5000行就很难掌控。
C++将data与function封装在类里面,并创建了类型。在类型中,data一般是private,私有的。C++通过访问权限来很好的解决了大型项目开发的问题。
2.3 头文件中的防卫式声明(guard)
#ifndef _COMPLEX_
#define _COMPLEX_
.
.//写头文件
.
#endif
- 防卫式声明主要是为了防止重复include,是在大学教学里面很容易被忽视的东西,但是在实际项目开发中却是很常用的,而且很多笔试题目都喜欢考防卫式声明的编写。
2.5 书写第一个class
#ifndef _COMPLEX_
#define _COMPLEX_
#include <iostream>
//class .....
class complex; //前置声明区
class complex{
// 类的声明
};
complex::function(){
//类的定义
}
#endif
一般类的书写,就分为三大块,基本来说,先写类的声明,类的定义,最后根据想法,再决定是否需要写前置声明。
2.6 class的声明
class complex //class head
{
//class body
public:
complex (double r = 0, double i = 0): re (r), im (i) { }
complex& operator += (const complex&);
double real () const { return re; }
double imag () const { return im; }
private:
double re, im;
};
类的声明由类名与类的主体构成,一般类的data都是私有的。
2.7 模板的初探
对于上面的代码,如果data换成 int, float,或者是其他类型的话,那是不是意味着要相应的写出对应的类呢?那这不是重复劳动了么。而模板的出现恰好解决了这个问题。
template<typename T>
class complex //class head
{
//class body
public:
complex (double r = 0, double i = 0): re (r), im (i) { }
complex& operator += (const complex&);
double real () const { return re; }
double imag () const { return im; }
private:
T re, im;
};
complex<int> A(0,5);
complex<double> D(1.1,6.2);
通过模板,将所要求的类型,通过T进行绑定。如果我要用int,那就指定T为int。
3. 构造函数
3.1 inline函数
class complex{
};
inline void complex::function(){}
在构建类,class,的时候,class body里面是类的本体,无需添加内联函数。而如果声明在本体,定义在外部,则考虑添加内联函数。
或者更广泛的来说,在C++里面调用类的相关函数的时候,都可以加上inline。
inline与宏类似,但是还是有一定的区别。
- inline 定义的类的内联函数,函数的代码被放入符号表中,在使用时直接进行替换,(像宏一样展开),没有了调用的开销,效率也很高。
- 只是做预处理器符号表中的简单替换,因此它不能进行参数有效性的检测,也就不能享受C++编译器严格类型检查的好处.
3.2访问级别 (access level)
class complex{
public:
private:
};
访问级别来讲的话,一般大部分的函数都放在public里面,几乎全部的数据都是放在private里面。
3.3 构造函数constructor(ctor)
class complex{
public:
complex(double r = 0, double i = 0)
:re(r), im(i)
{...}
private:
double re, im;
};
书写构造函数的四个注意点:
- 构造函数的函数名与类名相同
- 构造函数没有返回值。(构造函数不会被外部调用,只有在创建类的对象的时候被使用,因此创建的对象,那就是类本身,无需返回值)。
- 构造函数允许有默认参数(default argument)
- 构造函数特有初始化列表(initization list)。每次初始化的时候,都应用初始化列表 initization list 初始化
一个变量的生成分成两个阶段,初始化和赋值。如果不用初始化列表对成员变量进行赋值,则跳过了初始化阶段,这样虽然也对,但是效率降低。
一般而言,不带指针的类类里面,大部分是不需要写析构函数。
构造函数,是可以被重载的,但是被重载时要避免有歧义的代码,尤其是当构造函数中有默认参数的时候,更应该仔细考虑。
例如:
class complex
{
public:
complex(double r = 0, double i = 0)
:re(r), im(i)
{...}
1) complex()
:re(0), im(0)
{...}
private:
double re, im;
};
这段代码中的 1) 就是重载失败的案例,如果用户调用,complex()初始化的话,就会让编译器无法知道调用哪个构造函数而产生错误。