清华大学 C++ 学习笔记及部分代码

课件整理以及下载地址: github
有待上传

第三章

3.6 引用类型

定义一个引用时,必须初始化,且被初始化后不得改为指向其他对象。

3.8 内联函数

不能有循环语句和switch语句

3.9 constexpr函数

编译期间可计算的函数,可以用来初始化常量

3.11 函数重载

编译器不以返回值来区分函数。

第四章

4.3.1 类定义

class 类名称
{
public: 公有成员(外部接口)
private: 私有成员
protected: 保护型成员
};

类的成员函数

  • 在类中声明函数原型,在类外给出函数体实现
  • 在类内直接给出函数体,形成内联成员函数

4.4.1 构造函数

构造函数可以重载
初始化列表

Clock::Clock(int newH, int newM, int newS):
    hour(newH), minute(newM), second(newS){
}

4.4.4 委托构造函数

Clock::Clock(): Clock(0,0,0){}

4.4.5 复制构造函数

形参为本类对象的引用(引用加const)

public:
    Clock(const Clock &a);
}

复制构造函数被调用的三种情况

  1. 定义时以本类另一个对象作为初始值
  2. 调用函数时,使用实参对象初始化形参对象
  3. 返回值是类的对象

4.5 析构函数

public:
    ~Clock();

4. 6. 1 类的组合

首先对初始化列表中列出的成员进行初始化,初始化次序设成员在类体中定义的次序,无出现的调用默认构造函数

4.6.3 前向引用声明

class B;
class A{
public: 
    void f(B b);
}
class B{
public: 
    void f(A a);
}

4.8.1 结构体

默认数据为public,特殊的类

4.8.2 联合体

成员公用同一联合体。

union Mark{
    char grade;
    bool pass;
    int percent;
};

4.8.3 枚举类

enum class 枚举类型名:底层类型{枚举值列表};

强作用域,其作用域限制在枚举类中

Type::General

转换限制,枚举类对象不可以与整型隐式地互相转换

第五章

5.2 标识符的作用域与可见性

作用域

  • 函数原形作用域,作用域仅限于()
  • 局部作用域
  • 类作用域
  • 文件作用域:开始于声明点,结束于文件结束

5.2 对象的生存期

静态生存期
与程序的运行期相同:在文件作用域中声明的对象,块作用域中声明的用static修饰的对象,只会被初始化一次,不初始化默认为0。
动态生存期
每次进入作用域,都重新初始化

5.3.1 类的静态数据成员

  • 用关键字static声明
  • 为该类的所有对象共享,静态数据成员具有静态生存期
  • 必须在类外定义和初始化
class Point{
private:
    int x,y;
    static int count;
public:
    Point(int x=0, int y=0):x(x), y(y){
    count++;
    }
}
int Point::count = 0;

5.3.1 类的静态函数成员

静态函数用来处理静态数据,不知道哪个对象调用的静态函数

class Point{
public:
    static void showCount(){
        cout<<"Object count = "<< count << endl;
    }
}

void main(){
    Point::showCount();
}

5.4 类的友元

class Point{
public:
    friend float dist(Point &a, Point &b);
}

float dist(Point &a, Point &b){
    double x = a.x - b.x;
    double y = a.y - b.y;
    return static_cast(sqrt(x*x + y*y));
}

类的友元关系是单向的

class A{
    frind class B;
private:
    int x;
}
class B{
public:
    void set(int i);
private:
    A a;
}
void B::set(int i){
    a.x = i;
}

5.6 共享数据的保护

  • 常对象:必须进行初始化,不能被更新
  • 常成员:常函数成员(不更新对象的数据成员, const在最后,区分重载函数的因素,常对象只能调用常成员函数)常数据成员只能在初始化列表中初始化。
  • 常引用:被引用的对象不能被更新

5.7 多文件结构和预编译命令

外部函数:所有类之外声明的,具有文件作用域的函数,都可以在不同的编译单元中被调用,只要在调用之前进行引用性声明即可。
编译预处理

  • include<文件名> ,系统目录下搜索

  • include"文件名",首先在当前目录中搜索,若没有,再按标准方式搜索。

  • if … #endif 条件编译指令

第六章

6.2.2 数组的储存与初始化

  • 如果不作任何初始化,局部作用域的非静态数组中会存在垃圾数据,static数组中的数据默认初始化为0
  • 只对部分元素初始化,剩下的自动被初始化为零。

6.2.3 一维数组应用举例

读取单个字符

while(cin.get(c)){
}

6.4 对象数组

初始化

Point a[2] = {Point(1,2), Point(3,4)};

6.5 基于范围的FOR循环

int array[3] = {1,2,3};
for (int & e:array)
{
    e += 2;
    std::out<

6.6.1 指针的概念、定义

*寻址;&取地址

6.6.2 指针的初始化和赋值

指针变量的初始化
存储类型 数据类型 *指针名 = 初始地址;
不要用内部的非静态指针初始化静态指针
void类型的指针

void *pv;
int = 5;
pv = &i;
int *pint = static_cast(pv);
cout << *pint << endl;

指向常量的指针
const指针,不能通过指向常量的指针改变所指对象的值,但指针本身可以改变,可以指向另外的对象。(只读指针

int a;
const int *p1 = &a;
int b;
p1 = &b; //正确,指针本身可以改变
*p1 = 10; //错误,不能通过指向常量的指针改变所指对象的值

指针类型的常量

int a;
int * const p2 = &a;
p2 = &b; //错误,指针本身的值不能被改变

6.6.3 指针的算术运算、关系运算

  • 指针p加上n:指向当前位置后方第n个数据的起始位置
  • 指针可以和零进行关系运算

6-2.1.2 指针数组

int line1[] = {1,0,0};
int line2[] = {0,1,0};
int line3[] = {0,0,1};
int *pLine[3] = {line1, line2, line3};
cout << pLine[0][0] <

6-2.2.1 以指针作为函数参数

void print(const int *p, int n); 
//常指针:不能修改指针修改的量

6-2.2.2 指针类型的函数

不要将非静态局部地址用作函数的返回值
用new操作取得的内存地址返回给主函数是合法有效的。

6-2.2.3 指向函数的指针

数据类型 (*函数指针名)();

含义:函数指针指向的是程序代码存储区
功能:通过函数指针作为形参,函数回调

int compute(int a, int b, int(*func)(int, int)){
    return func(a,b);
}

int max(int a, int b){
    return (a>b)?a:b};
}

int sum(int a, int b){
    return a + b;
}

6-2.3 对象指针

类名 *对象指针名;

this指针:隐含于类的每一个非静态成员函数中

6-2.4.1 动态内存与释放内存

new 类型名T(初始化列表)

delete 指针p //释放内存操作符

6-2.4.2 申请与释放动态数组

new 类型名T[数组长度]
delete[] 数组名p //没有[]只释放首元素
new 类型T[第1维长度][第2维长度]//返回指向数组的指针

用类封装动态数组

class ArrayOfPoints{
public:
    ArrayOfPoints(int size): size(size){
        points = new Points[size];
    }
    ~ArrayOfPoints(){
        delete[] points;
    }
}

points.element()返回引用,可以作为左值被修改

6-2.5 智能指针

unique_ptr: 不允许多个指针共享资源
stared_ptr: 多个指针共享资源

6-2.6 VECTOR对象

vector<元素类型>数组对象名(数组长度)
for (auto e:v)
    std::cout << e << std::endl;

6-2.7.1 深层复制与浅层复制

浅层复制

在这里插入图片描述

深层复制

在这里插入图片描述

6-2.7.2 移动构造函数

class IntNum{
private:
    int *xptr;
public:
    IntNum(int x = 0):xptr(new int(x)){}
    IntNum(const IntNum &n):xptr(new int(*n.xptr))//深层复制构造函数
    IntNum(IntNum &&n) xptr(n.xptr){
        n.xptr = nullptr;
    } // &&是右值引用,移动复制函数
    ~IntNum(){
        delete xptr;}
};

6-2.8.1

字符串常量

const char *STRING1 = "program";
char str[] = "program";

6-2.8.2

string() //默认构造函数
string(const char *s)
string(const string& rhs)
s+t//字符串拼接

getline可以输入整行字符串,第三个参数设置分隔符

7.3 继承方式

  • 公有继承:基类的public和protected成员属性保持不变,基类的private成员不可直接访问
  • 私有继承:基类的public和protected成员以private身份出现在派生类中。派生类的成员函数可以直接访问基类中的public和protected成员,但是派生类的对象不能直接访问从基类继承的任何成员。
void move (float offX, floot offY) {
    Point::move(offX, offY);
}

  • 保护继承:基类的public和protected都以protected身份出现在派生类中。成员函数可以直接访问基类中的public和protected成员,派生类的对象不能直接访问从基类继承的任何成员。

7.4 基类与派生类类型转换

公有派生类对象可以被当作基类的对象使用

  • 派生类的对象可以隐含转换为基类对象
  • 派生类对象可以初始化基类的引用
  • 派生类的指针可以隐含转换为基类的指针
    但是基类指针只能调用基类的函数

7.5 派生类的构造函数

派生类新增成员由派生类定义构造函数

派生类名::派生类名(基类所需形参,本类成员形参):基类名(参数表),本类成员初始化列表
{
    //其他初始化;
}

构造函数的执行顺序

  1. 调用基类构造函数
  2. 对初始化列表中的成员进行初始化
  3. 执行派生类的构造函数体

7.5.3 派生类的复制构造函数

基类复制构造函数的实参是派生类对象的引用

C::C(const C &c1): B(c1){...}

7.5.4 派生类的析构函数

不需要显式地调用基类的析构函数,系统会自动地隐式调用。先析构派生类,再析构基类(顺序与构造相反)。

7.6.1 访问从基类继承的成员

当派生类与基类中有相同成员时,若未特别限定,则通过派生类对象使用的是派生类中的同名成员。如要通过派生类对象访问基类中被隐藏的同名成员,应使用基类名和作用域::来限定。
如从不同基类继承了同名成员,通过基类名来限定

7.6.2 虚基类

以virtual说明基类继承方式

class B1: virtual public B

用来解决多继承时可能发生的对同一基类继承多次而产生的二义性问题
虚基类的成员是由最远派生类的构造函数初始化,其他类对虚基类构造函数的调用被忽略。

8.2 运算符重载

  1. 双目运算符重载为成员函数
函数类型 operator 运算符(形参){
...}
Complex operator + (const Complex &c2) const;
Complex Complex::operator + (const Complex &c2) const{
    return Complex(real + c2.real, imag + c2.imag);
}

  1. 单目运算符重载为成员函数
    2.1 前置单目运算符 U oprd相当于oprd.operator U()
    2.2 后置单目运算符 ++和–,重载函数需要有一个int形参
Clock& operator ++();//前置
Clock operator ++(int);//后置
Clock& Clock::operator ++(){
    second++;
    if (second >= 60){
        second -= 60;
        minute++;
        if (minute >= 60){
            minute -= 60;
            hour = (hour + 1)%24;
        }
    }
    return *this;
}

Clock& Clock::operator ++(int){
    Clock old=*this;
    ++(*this);
    return old;
}

  1. 运算符重载为非成员函数
    函数的形参代表自左至右排序的各操作数
    在类声明中将重载函数声明为友元函数

8.3.1 虚函数

  • 运行阶段动态绑定
  • 构造函数不能是虚函数
  • 虚函数的声明
virtual 函数类型 函数名(形参表)

虚函数声明只能出现在类定义中的函数原型声明中,而不能再陈源函数实现的时候。虚函数不能写成内联函数

  • 派生类不写virtual声明也是虚函数,一般也会写,增加程序的可读性

8.3.2 虚析构函数

class Base{
public:
    virtual ~Base();
}
Base::~Base(){
    cout<<"Base dstructor"<

输出结果为:
Derived destructor
Base destructor

8.3.3 虚表与动态绑定

在这里插入图片描述

8.4 抽象类

纯虚函数:在基类中声明的虚函数,在基类中没有定义。只要有一个虚函数,即为抽象类。抽象类不能定义对象

virtual 函数类型 类型名(参数表)=0

8.5 Override和final

函数签名完全一致。在派生类中声明override的虚拟函数,编译器会检测基类中是否存在具有相同函数签名的虚函数。若不存在,会报错。
不希望派生出新的类,或函数不允许被覆盖,声明为final

9.2.1 函数模板

template
T abs(T x){
    return x<0?-x:x;
}
int main(){
    int n = -5;
    cout<

自定义的类,需要重载模板中的运算符,才能作为类型实参。

9.2.2 类模板

template<模板参数表>
class类名{类成员声明}

templage 
class Store{
private:
    T item;
public:
    T &getElem();
}
T &Store::getElem(){
    return item;
}

9.4 数组类模板

直接访问的线性群体
返回引用可以作左值
重载指针运算符,语法要求不指定返回值类型

Array:: operator T *(){
    return list;
}

10.2.2 STL简介

将迭代器作为算法的参数,而不是把容器直接作为算法的参数。
容器

  • 顺序容器
  • 有序关联容器
  • 无序关联容器
    迭代器
  • 可以使用++获取指向下一个元素的迭代器
  • 可以使用*访问迭代器所指向的元素
    输出流迭代器

10.3 迭代器

输入流迭代器

istream_iterator

输出流迭代器

ostream_iterator

读入实数,平方输出

transform(istream_iterator(cin), istream_iterator(), ostream_iterator(cout, "\t"), square);

你可能感兴趣的:(清华大学 C++ 学习笔记及部分代码)