c++学习知识点

c++学习

一、基础知识

  1. bool 非0为真(负数也为真)

  2. inline 内联函数,以内存为代码,运行时间加快

  3. 函数重载:(1)函数名相同 (2)参数列表不同

  4. 参数缺省:定义给其中一个形参一个默认值,调用时可以少写一个实参值
    使用:声明给默认值,调用函数时不给

  5. 引用:int mum=0;

​ int& dd=num; &解析引用符

  1. 命名空间:组织和重用代码的编译单元

    Namespace ::作用域符 相当于“里面的”

  2. new 相当于 malloc 申请内存

    delete 相当于free释放内存

// 1 申请单个内存
int* p1 = new int;
*p1 = 0;
// 2 申请单个内存且初始化
int* p2 = new int(999);
cout<<"*p2 = "<<*p2<<endl;
// 3 批量申请(连续的内存)
int* p3 = new int[10];
for(int i = 0; i<10; i++)
{
    p3[i] = i;
    cout<<"p3["<<i<<"] = "<<p3[i]<<endl;
}
delete p1;
delete p2;
delete[] p3;

二、面向对象

  1. 对象在程序内抽象为:属性+行为(即数据+函数)

  2. 三(四)个关键词

    封装(会用就行),继承,多态(不同情况做不同的事),(抽象)

  3. 在类class的外面访问private,通过一个公有成员函数访问

  4. c++结构体允许有函数

  5. string类:char ch = str[2]; ch = str.at(1); str.length();str.empty(); 空:ture 非空:false

    str.clear(); str == str; 判断是否相同

// 语法
class 类名
{
    // 默认是私有的
       // 成员:1 数据 2函数
    // 访问权限修饰关键字
    public:     // 共有的
       // 成员:1 数据 2函数
    private:    // 私有的
       // 成员:1 数据 2函数
    protected:  // 保护的
       // 成员:1 数据 2函数
};

三、构造函数与析构函数

1. 构造函数

特殊成员函数——创建对象赋初值

(1)构造函数名与类名相同

(2)无返回值类型(例如void),也无返回值(例如return 0)

(3)参数无限制,故可重载

(4)有低保

使用注意:

(1)构造函数在class内声明,在class外实现

(2)构造函数在创建对象时会自动调用(低保)

在c++中const变换时把变量改为常量

在c语言中const时把变量改为只读类型

故而当数据成员必须初始化,但不能在构造函数中幅值,用成员初始化列表的方式给数据成员赋值。(例如const,引用)

public:
    MyClass(int i);
...
Myclass::MyClass(int i):id(i)
{
    
}
2. 析构函数

对象生命周期结束时进行清理(会自动)

(1)析构函数名与类名相同,在前面加一个~

(2)无返回值类型(例如void),也无返回值(例如return 0)

(3)有低保

注意:

(1)因果关系:不是因为调用析构函数,对象生命周期结束;而是因为生命周期结束,调用了析构函数。

(2)任意一个类只有一个析构函数,且在公有属性(public)下。

3.拷贝构造函数

完成一个复制过程,参数是一个类的对象的引用

(1)先得是构造函数,第一个参数是类的引用

(2)有低保:没写系统会给,将成员一一赋值

   MyClass(const MyClass& obj){}

构造与析构的顺序:先构造的后析构

调用时机:

(1)使用一个对象对另一个对象初始化

(2)使用一个对象构造另一个对象

(3)函数的参数是类的对象

(4)函数的返回值是类的对象

深拷贝:指针不能直接赋值,不然两指针指向同一内存,需new一个新的内存,然后把值赋入新的内存中

解决方法:声明一个私有的private的拷贝构造函数,只声明不定义,主动让程序报错

四、继承与派生

1.继承与派生

在原来类基础上快速增加新功能,不要影响源代码,即创建新方式——子类(派生类)

继承与派生为同一过程在不同角度的名称

单继承 —— 一个父类 多继承 —— 多个父类

2.继承权限

(1)公有继承public (2)私有继承private (3)保护继承protected

注:继承是子类继承父类的全部成员

公有继承public私有继承private保护继承protected
publicpublicprivateprotected
private不可访问不可访问不可访问
protectedprotectedprivateprotected

多级继承:仅需要分析直接父子关系

3.父子关系

(1)派生类的构成:除过基类函数的构造函数与析构函数以外的部分(因为存在“低保”)

(2)派生类与基类关系:派生类对象可当作基类对象来使用,即用父类的地方可用子类,基类对象不是派生类对象

​ 父类对象可由子类对象幅值(因为父类小,子类大,父类有的子类都有),但是子类对象不能由父类幅值

​ 父类指针可指向子类对象(因为父类指针短,子类指针长),但是子类指针不可指向父类对象

(3)派生类的构造析构顺序与上述一直,先构造的后析构

4.菱形继承

可以采用虚继承的方法,virtual 多了两个虚指针,在给aa赋值时,虚指针自动判断重复只取其中一个,只多了两个虚指针所占用的内存.

五、多态

1.联编

计算机彼此关联的过程(映射)

(1)动态联编:运行时才知道执行什么代码

(2)静态代码

动态联编条件:

(1)拥有虚函数成员的类

(2)有继承关系,并且有虚函数类为父类

(3)用基类指针调用派生类对象(虚函数成员)

2.多态

虚函数:在函数前加virtual,所有虚函数存入虚函数表(有低保),虚函数可以被继承,虚函数表不能被继承,虚函数表记录类里面的虚函数指针(首地址)。

父类析构不虚析构可能会造成仅清理父类内存,清理不干净,使用父类虚析构保证能调到子类大的虚析构。

3.纯虚函数

纯虚函数:没有函数体的虚函数,在子类中实现父类纯虚函数。

virtual void test_func() = 0;

析构函数写纯虚函数得再类外实现(例外)。

抽象类:普通类并且用于一个或一个以上的纯虚函数,不允许实例化对象,即取定义对象,可以去定义指针。

4.final关键字

(1)权限掠夺者:终结操作

(2)掠夺函数权限:组织重写(虚函数)

void test_func() final;

(3)掠夺类的权限:阻止派生(无子类)

class Father final;

纯虚函数:

virtual void test() final = 0;

六、运算符重载

1.重载

赋予运算符不同功能,即定义一个函数写做什么事即重载规则。

// 返回值类型  函数名(形参列表) {}
// 函数名:operator运算符名称
obj_1.operator+(obj_2);    // obj_1 + obj_2
obj_2.operator+(obj_1);    // obj_2 + obj_1

在类外定义全局函数用到私有对象,可以声明该函数为友元,即在声明前面加friend

一个对象赋值给另一个对象 —— 拷贝构造

其他赋值 —— 赋值函数

2.规则详解

(1)不是所有运算符都可重载

(2)不能改变结合性和优先级

(3)不能改变运算符的用法(目数:单目还是单目,双目还是双目;结合性:操作数在左还是左)

(4)运算符重载函数不能有默认的参数

(5)运算符重载函数可以作为类的成员函数(自己当作this指针,占一个参数的位置,故而参数数量减一,例如双目变单目)

,也可以作为全局函数(无this指针,该双目任然两个参数)

(6)箭头运算符 -> 下标运算符[] 赋值运算符 = 函数调用运算符() 只能以成员函数的形式重载

3.重载输入输出

(1)建议作为友元函数重载friend

(2)istream输入

(3)ostreanm输出

有返回值的调用可以作为其他函数的实参

4.注意事项

(1)语法很简单,主要是规则

(2)可以显式调用(写函数),也可以隐式调用(写运算符)

(3)注意与友元的联合使用

七、模板

1.模板与泛型编程

模板:实现类型参数化,进行传递

泛型编程:与类型无关的逻辑代码

2.模板分类

(1)函数模板:使用函数模板写模板函数

(2)类模板:使用类模板写模板类

3.函数模板

(1)定义

写代码的方式(语法),用来定义模板函数(数据模型通过参数传入)

(2)语法

/*
    通过函数模板定义模板函数
    template <typename Type_1, typename Type_2,...,typename Type_n>
    返回值类型 函数名(形参列表)
    {
        函数体;
    }
    
    函数名 <类型列表>(实参列表);
*/

(3)对比

a. 可重载

b. 模板函数与普通函数重载,先调用普通函数

4.类模板

(1)定义

类的框架,指定数据类型才能定义对象

(2)语法

/*
    template <类型参数列表>
    class 模板类名
    {
        成员;
    };
    类型参数列表: <class T1,...,class Tn>
    
    // 创建对象时指定类型
    MyData<char, float> data_3(68, 3.14f)
    data_3.shouData();

*/

(3)类模板做函数的参数

// 1
void test_Func_1(MyData<int, double>& obj)
{
    obj.shouData();
}
// 2
template <typename TT1, typename TT2>
void test_Func_2(MyData<TT1, TT2>& obj)
{
    obj.shouData();
}
// 3 
template <class T>
void test_Func_3(T& obj)
{
    obj.shouData();
}
5.类模板和继承
template <class F_Type>
class Father
{
public:
    F_Type m_F_val;
};
class Son : public Father<int>
{
public:
    int m_S_Val;
}

注意事项:

(1)因为给对象类型,故一开始链接不到

(2)模板声明定义实现需要写在一个文件类,后缀用.hpp

6.模板与友元

即在模板中实现友元函数

若可直接在类中实现就写入类中实现;

若在类中声明,在类外实现需要首先在声明的()前添加一个<>;其次注意声明顺序,让变量互相认识

八、知识点补充

1.c++异常

程序执行期间出现问题

/*
    throw    抛出异常
    try      尝试有异常的代码
    catch    接受前面抛出的异常并解决
    
    try
    {
        //...
        直接或间接有throw
        不触发throw,代码正常向下运行;
        触发throw到catch,发生中断
        //...
    }
    
    catch(接受异常)
    {
        处理;
    } 
*/

if(b == 0)
{
    // 有异常情况 -> 打报告
    // throw抛出异常信息(支持多种类型)
    throw "这里有问题";
    // throw 666;
    // throw 's';
    // throw 3.14;
}

// 如果抛出异常后面语句不执行
int main()
{
    try
    {
        cout<<test(9,0)<<endl;
    }
    catch(const char* str)
    {
        cout<<str<<endl;
    }
    catch(int num)                            // 是哪个类型调用哪个catch,(...)其余类型,用法类似case里面的default
    {
        cout<<num<<endl;
    }
    catch(...)
    {
        cout<<"不对劲"<<endl;
    }
    return 0;
}
2.使用自定义异常

#include

exception 为共同父类,利用其去定义自定义类

3.文件流

(1) 流的概念

数据无结构化传递(抽象)

iostream - 输入输出流

(2) fstream的使用

file stream 即文件流 – 操作文件

(3) 常见的成员函数

#include<fstream>
int main()
{
    fstream obj;
    obj.open("文件路径", ios::in);  // ("文件路径", 打开方式);  可混合:ios::out | ios::trunc
    obj.close();
    obj.is_open(); // 判断是否成功打开
    obj.eof(); // 判断是否达到文件尾
    
    // 写
    obj.open("text_1.txt", ios::out);
    obj.put('s');
    char ch = 'a';
    obj.put(ch);
    obj.close();
    
    // 读
    obj.open("text_1.txt", ios::in);
    obj.get(ch);
    cout<<ch<<endl;
    obj.close();
}

// 利用二进制读写
obj.open("text_2.txt", ios::out);
int num = 99;
obj.write((const char*)& num, sizeof(int));
obj.close();

obj.open("text_2.txt", ios::in);
int val = 0;
obj.read((char*)& val, sizeof(int));
obj.close();
cout<<"val = "<<val<<endl;
4.使用重载输入输出

<< >> 直接按照流操作,中文占两个字符

obj.open("text_3.txt", ios::out);
obj<<"勇敢牛牛,不怕困难!";
obj<<"123"<<endl;
obj.close;
char str[64];
int num = 0;
obj.open("text_3.txt", ios::in);
obj>>str;
obj>>num;
cout<<str<<endl;
cout<<"num = "<<num<<endl;
obj.close;
5.c++11标准

(1) 初始化

int a = 0;
int b(2.1);
int m{4};
int n = {(int)3.14};

(2) 指针变量

int* p = NULL;     // 宏定义
int* p = nullptr;  // 关键字

(3) 自动类型auto

可自动推断,主要适用于明确类型,但懒得写

auto val(3.14)  // 此时auto 类型为double
auto val(3)     // 此时auto 类型为int

(4) decltype() 复制类型

int a = 0;
decltype(a) b;        // 根据a的类型定义一个和a类型一致的b变量
decltype((a))m = a;   // 给a取别名m

(5) 新的for规则

for(auto ch: str)
{
    cout<<ch<<" ";  // 使用ch便利str
}

(6) 给类型取别名

typedef int INT;
// 等价于
using INT = int;

typedef void(*PFun)();
// 等价于
using PFUN = void(*)();

(7) default 在类中用法

class CA
{
    public:
    CA();
}
CA::CA()= default;  // 默认调用默认构造

(8) final

class CA
{
    public:
    virtual void fun() final{};
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值