C++基础复习笔记(2)

一、函数的提高

1、函数默认参数

函数可以在定义或者声明时设置默认参数(但只能选择其中一种),函数被调用时,有传参则使用传参,没有则使用默认参数,且是从左到右匹配,故某个位置参数有默认值,那么从这个位置往后,从左向右,必须都要有默认值。
语法:返回值类型 函数名 (参数= 默认值){}

int func(int a, int b = 10, int c = 10) {
    return a + b + c;
}

2、函数重载

函数重载的作用是可以使用相同的函数名,提高复用性。
重载必须满足的条件是:
1、相同的作用域
2、函数名称相同
3、函数的参数类型或者个数或者顺序不同
注意: 函数的返回值不可以作为函数重载的条件
函数重载的调用一般不使用有无默认值区别重载,容易有歧义。

void func()
{
    cout << "func 的调用!" << endl;
}
void func(int a)
{
    cout << "func (int a) 的调用!" << endl;
}
void func(double a)
{
    cout << "func (double a)的调用!" << endl;
}
void func(int a ,double b)
{
    cout << "func (int a ,double b) 的调用!" << endl;
}
void func(double a ,int b)
{
    cout << "func (double a ,int b)的调用!" << endl;
}

二、类和对象

语法: class 类名{ 访问权限: 属性 / 行为 };
访问权限有三种:

  1. public 公共权限 类内可以访问 类外可以访问
  2. protected 保护权限 类内可以访问 类外不可以访问
  3. private 私有权限(默认类型)类内可以访问 类外不可以访问
//学生类
class Student
{
    public:
        string m_Name;
        int m_Num;

        void setName(string name)
        {
            m_Name = name;
        }
        void setID(int id)
        {
            m_Num = id;
        }
        void showStudent()
        {
            cout << "姓名:" << m_Name << endl;
            cout << "学号:" << m_Num << endl;
        }
};

1、构造函数和析构函数

  • 构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。
  • 析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。
    构造函数语法:类名(){}
  1. 构造函数,没有返回值也不写void
  2. 函数名称与类名相同
  3. 构造函数可以有参数,因此可以发生重载
  4. 程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次
    两种分类方式:
    按参数分为: 有参构造和无参构造
    按类型分为: 普通构造和拷贝构造
//1、构造函数分类
// 按照参数分类分为 有参和无参构造   无参又称为默认构造函数
// 按照类型分类分为 普通构造和拷贝构造

class Person {
public:
    //无参(默认)构造函数
    Person() {
        cout << "无参构造函数!" << endl;
    }
    //有参构造函数
    Person(int a) {
        age = a;
        cout << "有参构造函数!" << endl;
    }
    //拷贝构造函数
    Person(const Person& p) {
        age = p.age;
        cout << "拷贝构造函数!" << endl;
    }
    //析构函数
    ~Person() {
        cout << "析构函数!" << endl;
    }
public:
    int age;
};

//2、构造函数的调用
//调用无参构造函数
void test01() {
    Person p; //调用无参构造函数
}

//调用有参的构造函数
void test02() {

    //2.1  括号法,常用
    Person p1(10);
    //注意1:调用无参构造函数不能加括号,如果加了编译器认为这是一个函数声明
    //Person p2();

    //2.2 显式法
    Person p2 = Person(10); 
    Person p3 = Person(p2);
    //Person(10)单独写就是匿名对象  当前行结束之后,马上析构

    //2.3 隐式转换法
    Person p4 = 10; // Person p4 = Person(10); 
    Person p5 = p4; // Person p5 = Person(p4); 

    //注意2:不能利用 拷贝构造函数 初始化匿名对象 编译器认为是对象声明
    //Person p5(p4);
}

int main() {

    test01();
    //test02();

    system("pause");

    return 0;
}

//拷贝构造函数
Person(const Person& p) {
age = p.age;
cout << "拷贝构造函数!" << endl;
}
使用常量引用传递将拷贝对象传递过来供拷贝使用,即不用开辟新的空间,也不会修稿原对象的属性。

函数以对象作为形参,在参数传递是会调用拷贝构造,默认拷贝构造函数,对属性进行值拷贝。

//2. 值传递的方式给函数参数传值
//相当于Person p1 = p;
void doWork(Person p1) {}
void test02() {
    Person p; //无参构造函数
    doWork(p);
}

构造函数调用规则如下:

  • 如果用户定义有参构造函数,c++不在提供默认无参构造,但是会提供默认拷贝构造
  • 如果用户定义拷贝构造函数,c++不会再提供其他构造函数

2、浅拷贝和深拷贝

浅拷贝:简单的赋值拷贝操作
深拷贝:在堆区重新申请空间,进行拷贝操作

总结:如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题

如果属性中存在堆区开辟空间(new 数据类型())的情况,则需要在拷贝构造中设置深拷贝,开辟堆区赋值。在析构函数中,判断堆区开辟情况进行delete。

    //无参(默认)构造函数
    Person() {
        cout << "无参构造函数!" << endl;
    }
    //有参构造函数
    Person(int age ,int height) {
        
        cout << "有参构造函数!" << endl;

        m_age = age;
        m_height = new int(height);
        
    }
    //拷贝构造函数  
    Person(const Person& p) {
        cout << "拷贝构造函数!" << endl;
        //如果不利用深拷贝在堆区创建新内存,会导致浅拷贝带来的重复释放堆区问题
        m_age = p.m_age;
        m_height = new int(*p.m_height);
    }
    //析构函数
    ~Person() {
        cout << "析构函数!" << endl;
        if (m_height != NULL)
        {
            delete m_height;
        }
      }

3、初始化列表

C++提供了初始化列表语法,用来初始化属性
语法:构造函数():属性1(值1),属性2(值2)... {}

4、类对象作为类成员

//当类中成员是其他类对象时,我们称该成员为 对象成员
//构造的顺序是 :先调用对象成员的构造,再调用本类构造。因为对象成员也属于本类的成员,需要本类的所有“材料”备齐后,才构造本类。因此,先调用对象成员的构造,再调用本类构造。
//析构顺序与构造相反

5、静态成员

静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员
静态成员分为:

  • 静态成员变量
    • 所有对象共享同一份数据
    • 在编译阶段分配内存
    • 类内声明,类外初始化
  • 静态成员函数
    • 所有对象共享同一个函数
    • 静态成员函数只能访问静态成员变量
class Person
{
    
public:

    static int m_A; //静态成员变量   类内声明

    //静态成员变量特点:
    //1 在编译阶段分配内存
    //2 类内声明,类外初始化
    //3 所有对象共享同一份数据,任何函数、对象修改变量时都是对该内存的值进行操作。

private:
    static int m_B; //静态成员变量也是有访问权限的
};
int Person::m_A = 10;    //类外初始化
int Person::m_B = 10;

访问形式都可以通过对象或者通过类名访问:
对象.静态变量(函数)
类名::静态变量(函数)

静态变量函数和静态函数不占用对象空间,在C++中,类内的成员变量和成员函数分开存储,只有非静态成员变量才属于类的对象上。

6、对象模型和this指针

this指针的用途:

  • 当形参和成员变量同名时,可用this指针来区分
  • 在类的非静态成员函数中返回对象本身,可使用return *this
    Person& PersonAddPerson(Person p)
    {
        this->age += p.age;
        //返回对象本身
        return *this;
    }

可实现调用

Person p2(10);
p2.PersonAddPerson(p1).PersonAddPerson(p1).PersonAddPerson(p1);

因为p2.PersonAddPerson(p1)调用后,引用返回对象自身,即p2.PersonAddPerson(p1)调用后等价于对象p2,因此可以继续调用对象中的方法。关键在于return *this;和引用返回。this是指针,指向本对象,取this的指向值并返回。

C++中空指针(Person * p = NULL;)也是可以调用成员函数的
(p->ShowClassName();),但是也要注意有没有用到this指针
如果用到this指针,需要加以判断保证代码的健壮性,因为空指针下this = NULL。

const修饰成员函数

常函数:

  • 成员函数后加const后我们称为这个函数为常函数
  • 常函数内不可以修改成员属性
  • 成员属性声明时加关键字mutable后,在常函数中依然可以修改
    void MyFunc() const {
    }

常对象:

  • 声明对象前加const称该对象为常对象
  • 常对象只能调用常函数
const Person person; //常量对象 

7、友元

在程序里,有些私有属性 也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术,友元的目的就是让一个函数或者类访问另一个类中私有成员
使用时需要在类里用friend声明友元(全局函数、其他类、成员函数)

friend 全局函数
friend 类
friend 类::成员函数
声明为友元即可让友元访问本类的private。

8、运算符重载

//成员函数实现 + 号运算符重载
    Person operator+(const Person& p) {
        Person temp;
        temp.m_A = this->m_A + p.m_A;
        temp.m_B = this->m_B + p.m_B;
        return temp;
    }

存在返回自身(运算后整体还是自身类型,如i++后,整个i++还是原本自身i)的符号重载

    MyInteger& operator++() {
        //先++
        m_Num++;
        //再返回
        return *this;
    }

9、继承

继承的好处:==可以减少重复的代码==
class A : public B;
A 类称为子类 或 派生类
B 类称为父类 或 基类

继承中 先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反

  • 访问子类同名成员 直接访问即可
  • 访问父类同名成员 需要加作用域
    s.func();
    s.Base::func();
  • 菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义
  • 利用虚继承可以解决菱形继承问题
//继承前加virtual关键字后,变为虚继承
//此时公共的父类Animal称为虚基类
class Sheep : virtual public Animal {};
class Tuo   : virtual public Animal {};
class SheepTuo : public Sheep, public Tuo {};

10、多态

多态分为两类

  • 静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名
  • 动态多态: 派生类和虚函数实现运行时多态

静态多态和动态多态区别:

  • 静态多态的函数地址早绑定 - 编译阶段确定函数地址
  • 动态多态的函数地址晚绑定 - 运行阶段确定函数地址

11、 纯虚函数和抽象类

在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容
因此可以将虚函数改为纯虚函数
纯虚函数语法:virtual 返回值类型 函数名 (参数列表)= 0 ;
当类中有了纯虚函数,这个类也称为==抽象类==
抽象类特点

  • 无法实例化对象
  • 子类必须重写抽象类中的纯虚函数,否则也属于抽象类

在父类(抽象类)中写纯虚函数,子类继承后必须重写纯虚函数,否则子类还是抽象类,都要加关键字virtual

class Abtract
{
  public:
            virtual void fun() = 0;
}
class Concrete : public Abtract
{
  public:
            virtual void fun() 
             {
                    cout<< "fun 调用"<<endl;
               };
}

11、 虚析构和纯虚析构

多态使用时,如果子类中有属性开辟到堆区,那么父类指针(父类* cat = new 子类)在释放时无法调用到子类的析构代码
解决方式:将父类中的析构函数改为虚析构或者纯虚析构
虚析构和纯虚析构共性:

  • 可以解决父类指针释放子类对象
  • 都需要有具体的函数实现
    虚析构和纯虚析构区别:
  • 如果是纯虚析构,该类属于抽象类,无法实例化对象
    虚析构语法:
    virtual ~类名(){}
    纯虚析构语法:
    virtual ~类名() = 0;
    类名::~类名(){}
  1. 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
2. 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构
3. 拥有纯虚析构函数的类也属于抽象类

12、文件操作

包含的头文件:#include <fstream>
文件类型分为两种:

  1. 文本文件 - 文件以文本的ASCII码形式存储在计算机中
  2. 二进制文件 - 文件以文本的二进制形式存储在计算机中,用户一般不能直接读懂它们
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容