C++ 学习笔记06

一、析构函数


创建对象--->构造函数--->析构函数--->删除对象

1.作用

析构函数是一个特殊的成员函数 作用与构造函数相反
功能:当对象脱离其作用域(对象所在的函数已经调用完毕) 系统自动调用析构函数 析构函数往往做"清理善后"工作
声明:没有返回值 名字必须与类名同名 没有参数 名字前 ~
析构函数不能有参数,不能被重载

示例1

using namespace std;
class Person
{
private:
    int age;
public:
    Person(int age):age(age)
    {
        cout<<"构造"<<endl;
    }
    int getAge()
    {
        return age;
    }
    ~Person()
    {
        cout<<"析构"<<endl;
    }
};
int main()
{
cout<<”1---------------------”<<endl;
    Person* p = new Person(19);//构造
cout<<”2---------------------”<<endl;
    delete p;//析构
cout<<”3---------------------”<<endl;
    Person p1(20);//构造
cout<<”4---------------------”<<endl;
{//花括号本身就是一个作用域
Person p2(30);//构造   析构
}
cout<<”5---------------------”<<endl;
}
//main函数结束后  输出p1的析构

2.默认析构函数

如果没有显式的定义析构函数,会生成默认析构函数。
默认的析构函数:没有参数,没有逻辑

~Person()
{
}

练习1

设计一个Book类 包含图书的书名,作者成员 其中:书名和作者用字符型指针
char* name; 动态创建数组来保存字符串
char* author;
1.构造函数为作者及书名指针开辟空间并将传入的 书名和作者拷贝到数组中
Book(const char* name,const char* author)
2.一个析构函数,删除书名和作者数组delete[] name
3.成员函数print()输出数据

查看练习代码

#include <iostream>
#include <string.h>
using namespace std;
class Book
{
private:
    char* name;
    char* author;
public:
    Book(const char* name, const char* author):
        name(new char[20]),//使成员指针指向动态创建的数组
        author(new char[20])
    {
        strcpy(this->name, name);//将参数name指向的字符串,拷贝到this->name指向的数组中
        strcpy(this->author, author);
    }

    ~Book()
    {
        delete[] name;//释放在构造函数中动态创建的数组
        delete[] author;
    }
    void print()
    {
        cout<<name<<" "<<author<<endl;
    }
};

int main()
{
    Book b("c++ primer", "大神s");
    b.print();
    return 0;
}

二、常对象

常对象不能调用普通的成员函数。

1.常函数

1)常函数中的this是被const修饰的,在常函数中成员变量不能被修改,
2)常对象只能调用常函数

示例2

#include <iostream>
using namespace std;
class Person
{
private:
    int age;
public:
    Person(int age):age(age){}
void add() const    //常函数的修饰方式,把const写在()的右边
{
        //cout<<++age<<endl;//语法错误,常函数中不能修改成员变量
cout<<age<<endl;
cout<<”cont add”<<endl;
    }
void add()//常函数算重载,普通对象优先调用普通函数
{
cout<<age<<endl;
cout<<”normal add”<<endl;
}
};
int main()
{
    const Person p(20);
    p.add();
Person p2(10);
p2.add();//普通对象也能调用常函数
}

2.声明常对象

const 类名 对象名(实参)
类名 const 对象名(实参)
注意常对象:
(1)成员变量必须有初值
(2)只能调用常成员函数
功能:希望对象所有成员的值不被修改

示例3

#include<iostream>
using namespace std;
class Person
{
private:
    string name;
    int age;
public:
    Person(const string n,const int age);
    void show();//常函数算重载
    void show()const;
};

Person::Person(const string name,const int age):name(name),age(age)
{

}
void Person::show()
{
    cout<<"我是"<<name<<" 今年"<<age<<endl;
}
void Person::show()const
{
    cout<<"我是const "<<name<<" 今年"<<age<<endl;
}
int main()
{
        const Person a("昆山龙哥",36);
        a.show();//常对象只能调用常函数

        Person b("昆山电池动车哥",43);
        b.show();//普通对象优先调用普通函数
}

3.mutable

mutable修饰的成员变量可以在常函数中修改

示例4

#include <iostream>
using namespace std;
class Person
{
private:
    string name;
    int age;
    mutable int a;//a可以在常函数中被修改
public:
    Person(int age,string name,int a):age(age),name(name),a(a){}
    void show()
    {
        cout<<age<<" "<<name<<endl;
    }
    void show() const
    {
        ++a;//因为a是mutable修饰的成员,所以可以在常函数中修改
        cout<<age<<"$$$"<<name<<" "<<a<<endl;
    }
};

int main()
{
    Person p(20, "小明",10);
    p.show();
    const Person p2(30, "小强",10);
    p2.show();
}

三、友元

1.友元的概念

友元可以访问与其好友关系的类中的所有成员(包括private protected public)
使用friend关键字进行修饰
友元:友元函数和友元类

注意:但友元破坏类的封装特性,慎用!

友元的特点:

  1. 友元是单向的
class B;
class A
{
friend class B;
};
//B是A的友元,但是A不是B的友元。
  1. 友元不能传递
    B是A的友元,C是B的友元,A和C没有友元关系。
  2. 友元不能继承

2.友元函数

将普通函数声明为友元函数 friend + 函数声明

示例5

class Person;
void display(Person& p);
class Person
{
friend void display(Person& p);//声明display函数是Person类的友元函数,在display函数中可以访问Person类中的私有成员
private:
    string name;
    int age;
public:
    Person(string name,int age):name(name),age(age)
    {

    }
    void show()
    {
        cout<<name<<" "<<age<<endl;
    }
};
void display(Person& p)//Person& p = a;
{
    cout<<p.name<<" "<<p.age<<endl;//因为display是Person类中友元。所以可以直接访问Person类中私有成员
}
int main()
{
    Person a("tom",10);
    disPlay(a);
}

练习2

  1. 有个学生类Student
    包括:私有成员:姓名 成绩
    void setData(string name, int score)给成员变量赋值,如果使用匿名对象对数组初始化,setData函数就没有用了。void show();
  2. 在main定义 student数组5个元素并赋值 Students[5]
  3. 设计一个全局友元函数 比较两个学生的成绩的高低 int compare(Student& a, Student& b);
    a>b return 1; a<b return -1; 相等 0
  4. 求出最高分和最低分的学生

查看练习代码

#include <iostream>
#include <string>
using namespace std;
class Student
{
friend int compare(Student& s1, Student& s2);// 友元的声明写在类的任何位置都可以,习惯于写在很醒目的位置
private:
    string name;
    int score;
public:
    Student(string name, int score):
        name(name), score(score)
    {

    }
    void show()
    {
        cout<<name<<" "<<score<<endl;
    }
};
int compare(Student& s1, Student& s2)
{
    if(s1.score < s2.score)
    {
        return -1;
    }
    else if(s1.score > s2.score)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}
int main()
{
    Student students[5] = {
        Student("小明", 18),
        Student("小强", 81), 
        Student("小红", 60), 
        Student("小兰", 59),
        Student("小绿", 61)
    };
    int maxIndex = 0;
    int minIndex = 0;
    for(int i = 1;i < 5;i++)
    {
        if(compare(students[maxIndex], students[i]) == -1)
        {
            maxIndex = i;
        }
        else if(compare(students[minIndex], students[i]) == 1)
        {
            minIndex = i;
        }
    }

    students[maxIndex].show();
    students[minIndex].show();
    return 0;
}

3.友元类

friend + 类声明

示例6

#include <iostream>
#include <string>
using namespace std;
class Teacher;
class Student
{
friend class Teacher;//声明Teacher类是Student类的友元类,Teacher类中的每个成员函数都可以访问Student类中的私有成员。
private:
    string name;
    int score;
public:
    Student(string name, int score):
        name(name),
        score(score)
    {}
};
class Teacher
{
public:
    void look(Student& s)
    {
        cout<<s.name<<" "<<s.score<<endl;//因为Student声明了Teacher类是Student类的友元类,所有Teacher类中的所有成员函数都能直接访问Student类中私有成员
    }
};
int main()
{
    Teacher t;
    Student s("小张",19);
    t.look(s);
}

四、C++中的异常机制

1.异常是什么?

异常是程序在执行期间产生的问题。C++ 异常是指在程序运行时发生的特殊情况,比如尝试除以零的操作。

2.检测异常的三个步骤:

检查(try) 抛出(throw) 捕捉(catch)

  1. try: try 块中的代码标识将被激活的特定异常。它后面通常跟着一个或多个 catch 块。
  2. throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
  3. catch: 在您想要处理问题的地方,通过异常处理程序捕获异常。catch 关键字用于捕获异常。

3.try...catch语法

try 
{
    被检查语句
}
catch(异常处理的类型 变量名)
{
    进行异常处理的语句;
}

示例7

#include<iostream>
using namespace std;
int mydiv(int a,int b)
{
    if(b==0)//分母为0,说明发生了异常
    {
        cout<<"throw....."<<endl;
        throw b;//抛出一个异常对象,异常对象可以是基本类型,也可以是类类型。
    }
    return a/b;
}
int main()  
{
    int a=10;
    int b=0;
    try
    {
        int result = mydiv(10,0);//因为mydiv函数可能会抛出异常,所以写在try语句块中用来捕捉异常。
如果mydiv抛出异常,会马上终止try语句块
如果mydiv没有抛出异常,会把try语句块执行完
        cout<<result<<endl;
    }
    catch(int e)//在catch中处理try中抛出的异常,catch()中的对象,就是try中抛出的异常对象
    {
        cout<<"catch int "<<e<<endl;
    }
}

示例8

捕捉多异常

#include <iostream>
using namespace std;
class ExceptA//专门用来表示异常的类
{
public:
    void show()
    {
        cout<<"异常A"<<endl;
    }
};

class ExceptB//专门用来表示异常的类
{
public:
    void show()
    {
        cout<<"异常B"<<endl;
    }
};

int div(int a, int b)
{
    if(b == 0)
    {
        ExceptA e;
        throw e;//抛出异常对象ExceptA 类型
    }
    return a/b;
}

double div(double a, double b)
{
    if(b == 0)
    {
        ExceptB e;
        throw e;//抛出异常对象ExceptB 类型
    }
    return a/b;
}

int main()
{
    try
    {
//同一时刻只能抛出一个异常
        div(1, 0);//当这里抛出ExceptA 类型异常时,整个try就结束了
        div(1.0, 0.0);
    }
    catch(ExceptA e)//专门用来处理ExceptA 类型异常的catch
    {
        e.show();   
    }
    catch(ExceptB e)//专门用来处理ExceptB 类型异常的catch
    {
        e.show();
    }
    catch(...)//处理其他类型的异常
    {
        cout<<"other e"<<endl;  
    }
}

4.应用中的异常检测

int main()
{
    do
    {
        if(1)
        {
            cout<<"异常1"<<endl;
            break;//发现异常直接停止do-while结构
        }
        if(2)
        {
            cout<<"异常2"<<endl;
            break;
        }
    }while(false);//do-while是为了break提供执行环境
    return 0;
}

练习3

给出三角形三边 a、b、c 求三角形周长
只有a+b>c b+c>a a+c>b 才能构成三角形 设置异常处理 对不符合三角形条件的 输出警告信息 不予计算

查看练习代码

class TriangleExcept
{
private:
    int a;
    int b;
    int c;
public:
    TriangleExcept(int a, int b, int c):a(a),b(b),c(c)
    {}

    void print()
    {
        cout<<a<<" "<<b<<" "<<c<<"can not a triangle"<<endl;
    }
};
int triangleLength(int a, int b, int c)
{
    if(a+b<=c || a+c<=b || b+c<=a)
    {
        TriangleExcept e(a, b, c);
        throw e;//创建三角形异常对象,并且抛出异常
    }
    return a+b+c;
}

int main()
{
    try
    {
        int len = triangleLength(2, 2, 3);
        cout<<len<<endl;
    }
    catch(TriangleExcept e)
    {
        e.print();
    }
    return 0;
}

五、c++中静态成员

1.静态成员变量

  1. 属于整个类 静态成员变量只存储一份供所有对象使用
  2. 必须在类外单独初始化 而且只能全局进行 否则不会分配空间 编译报错

示例9

#include<iostream>
using namespace std;
class Stu
{
public:
    static int num ;//静态成员变量,它不属于任何一个对象。
};
int Stu::num = 10;//初始化类中的静态成员变量,要写在cpp文件中
int main()
{
    cout<<Stu::num<<endl;//访问静态成员变量
}

示例9 补充

class Student
{
private:
    static int num;   
public:
    void addNum()
    {
        num++;
    }
    void showNum()
    {
        cout<<num<<endl;
    }
};
int Student::num = 0;

int main()
{
    Student s1;
    s1.showNum();
    s1.addNum();
    s1.addNum();
    Student s2;
    s2.showNum();//因为所有的对象共用同一个静态成员变量,所以输出2
    return 0;
}

2.静态成员函数

  1. 没有this指针,所以静态成员函数不能访问本类中的非静态成员,静态函数只能调用静态成员
  2. 静态成员函数和本类的任何对象都没有关系!!!

示例10

#include<iostream>
using namespace std;
class Stu
{
private:
int age;
public:
    static int num;//静态成员变量
    static int get_num()//静态成员函数
    {
age = 10;//语法错误,因为静态成员函数中不能访问非静态成员
        return num;//静态成员函数中只能使用静态成员
    }
};
int Stu::num=89;
int main()
{
    cout<<Stu::get_num()<<endl; //通过类名直接访问静态成员函数。
Stu s;
cout<<s.get_num()<<endl;//这么写也不算语法错误,但是没有逻辑意义,因为静态成员函数get_num()中没有指向对象s的指针。
}

示例10 补充

class Student
{
private:
    static int num;

public:
    Student()
    {
        num++;
    }
    ~Student()
    {
        num--;
    }
    void addNum()
    {
        num++;
    }
    static void showNum()
    {
        cout<<num<<endl;
    }
};
int Student::num = 0;
int main()
{
    Student* p1 = new Student();
    Student* p2 = new Student();
    Student* p3 = new Student();
    Student* p4 = new Student();
    Student::showNum();//4
    //p4->showNum();//这么写虽然语法允许,但是不符合逻辑
    delete p1;
    delete p2;
    Student::showNum();//2
    delete p3;
    delete p4;
    Student::showNum();//0
    return 0;
}

六、设计模式——单例模式


设计模式就是编程的套路,解决指定问题的套路。它不是算法,是项目架构的设计套路。
设计模式是思想,没有固定的代码。

1.单例模式详解

End

本文标题:C++ 学习笔记06

本文链接:http://chisato.cn/index.php/archives/145/

除非另有说明,本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议

声明:转载请注明文章来源。

最后修改:2021 年 11 月 21 日 02 : 06 PM
如果觉得我的文章对你有用,请随意赞赏