资源来自:https://www.youtube.com/watch?v=2S-tJaPKFdQ&list=PL-X74YXt4LVZ137kKM5dNfCIC4tsScerb
第一讲:C++编程简介
基于对象、面向对象。类(class)之间相关联的代码。
class的经典分类:带指针、不带指针。
C++是第一个面向对象的语言,其他的诸如java等语言,也是面向对象的。
C++:包含C++语言、C++标准库的部分。标准库内含的东西逐渐增多,可以加以利用。
推荐书籍:C++Primer、The C++ Programming Language、Effective C++(侯捷、Scott Meyers)、The C++ Standard Library(STL源码剖析)
第二讲:头文件与类的声明
C++面向对象的处理方式:将数据和函数进行封装,使得某一些数据只能被相应的函数调用。防止C语言下,变量的全局性被外界函数调用而造成影响。实际上,C++的class本身类似于一个struct,本身相当于封装后,可以调用的一类数据与操作。
例:设计复数这种类时,数据类型需要设计一个实部和虚部,此外还需要定义复数的运算方式:加减乘除、共轭、正弦。设计字符串这种类型时,其实数据域里面只有一个指针。而,在访问整个字符串时,会访问到另外的内存。字符数据存在于内存中,由字符指针访问。而字符串这个类支持拷贝、输入、附加、插入等等操作方式。
当设计的类含有指针的时候,我们需要非常小心。Object Based面对的是单一class的设计,Object Oriented,面对的是多重classes的设计,class之间的关系。
C++程序代码的基本形式:有头文件、主程序等等
引用标准库:include <标准库内容>
引用自己写的库:include "complex.h"
头文件的写法:(防卫式声明)
#ifndef _COMPLEX_
#define _COMPLEX_
...
#endif
写这个代码的目的:可能会多次用到这个头文件,所以写一个防卫式声明。告诉编译器:一进来,如果没有定义出_COMPLEX_这个名次的话,就把它定义出来。所以,程序第一次引用它的时候才会定义并执行下述代码,而第二次再include的话,就不会进入主体了,这样就不会有重复的含入动作。
//我们写好的头文件引用格式就是:
#include "complex.h"
接下来,如何写一个头文件?
//防卫式声明
#ifndef _COMPLEX_
#define _COMPLEX_
//前置声明部分
#include <cmath>
class ostream;
class complex;
complex&
_doapl (complex* ths, const complex& r);
//类声明
class complex
{
...
};
//类定义
complex::function...
#endif
这个是头文件的主体框架,接下来进入class的声明部分:即上述类声明。
class complex //class head
{ //class body
public:
complex (double r = 0 , double i = 0)
: re (r) , im(i)
{ }
complex& operator += (const complex&);
double read () const { return re; }
double imag () const { return im; }
private:
double re, im;
friend complex& _doapl (complex*, const complex&);
};
private为内建的类型,只有内部的操作可以改变实部和虚部。
模板的概念:class template
template<typename T> //不会现在就把类型写死,将来再定
class complex
{
...
private:
T re, im;//这里的T是说,暂时还没有确定这里的类型。
}
//用法:
{
complex<double> c1(2.5, 1.5);
complex<int> x2(2, 6);
}
这里就使得类型的自定义得到扩展。更加方便。
第三讲:构造函数
class complex //class head
{ //class body
public:
complex (double r = 0 , double i = 0)
: re (r) , im(i)
{ }
complex& operator += (const complex&);
double read () const { return re; }
double imag () const { return im; }
private:
double re, im;
friend complex& _doapl (complex*, const complex&);
};
inline double
imag(constt complex& x)
{
return x.imag();
}
第二讲中出现的例子里面,class body部分写了三个函数。第一个函数是以括号的形式出现,表示其仅仅为声明出来了,而第二、三个函数都已经有刮号以及返回值了,因此是已经定义完成了。有些函数在body定义,有些在外面定义。
定义:inline(内联)函数。
函数在class body内被定义,就形成了一种inline。如上述的read()和imag()函数。
若函数是内联的,则会更加迅速。当然,有些函数是inline的,也不会被编译器做成inline的。函数太过复杂无法inline(简单理解)
上面的函数是在本体的外头写成的
public和private的意义:
public是公开的内容,可以被外界所视。而private是私有的内容,只有class内部才看得到。
数据部分应当放在private部分,应当是封装起来的,只有自己看的到。函数部分,也可以分成:外界使用和私用。若被外界使用,则应当放在public中,如果不被外界使用,则应当放在private中。
access level访问级别:
创建对象后,通过对象调用某一个函数。若直接cout << c1.re;是错误的,因为数据内部成员re是私有的,不是对外公开的。而cout << c1.read()是可以的,因为这个函数是公开的。
构造函数
如果想要创建对象,一个函数会被自动调用起来。
public:
complex (double r = 0, double i = 0) //这里的r、i都是默认实参(default argument)
: re(r), im(i) //这里的是初始列
{ }
构造函数的名称一定要与类的名称相同。
r,i为默认实参,可以进行数据的初始化。如果创建的时候没有指明,那么就按照给定的默认值赋值。除了构造函数,其他的函数也可以写出默认值来。
构造函数没有返回类型,因为构造函数就是用来创造对象的。是为了创建complex的,所以不必有return type.语法:自定义。上例中将输入的r、i放到re、im中。一方面,可以在大括号内写上赋值语句。另一方面,我们可以在构造函数中间行直接进行操作,叫initialization list初始列。这种特殊的构造函数才享有的写法:
: re(r), im(i)
{ }
这种写法的优点:一个变量的更改有两步,初始化和赋值。初始化步骤就在初始列上,直接在初始列上进行赋值,那么就会提高一定的效率。
最常看到的就是在这里设初始值。
不可能在类中直接调用构造函数,构造函数的意义仅仅是创建对象。这个函数自然而然会被调用起来。(补:析构函数,不带指针的类基本上不需要写析构函数,而有指针的情况才需要写析构函数)
构造函数可以有很多个。称为重载(overloading)
C++允许多个重载构造函数,C不可。
real函数的意义是取得实部,可以再加一个重载同名设置实部的函数。当然,需要去掉const。
在进行完重载之后,可能编译器最终编译出来的同名函数还是有一定区别的,这个时候不是人在看了。
可是,有一些情况,重载是非法的。
public:
complex (double r = 0 , double i = 0)
: re(r), im(i)
{}
complex() : re(0), im(0) {}
这种情况下,若在无参数情况下调用complex c1.第一个重载函数中虽然有参数,可是有初始化的处理;第二个重载函数中无参数,所以编译器会发生错误,不知道该调用哪一个函数了。综上所述,这种会引发冲突的重载函数是非法的。