C++【6】(两常两静一友)

290 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

一、常函数(常成员函数)和常对象

1.1 常函数

  • 常函数,也就是常成员函数
  • 在函数名参数最==右边加const==
  • 调用常成员函数和普通成员函数一样,不需要加 const
  • 常函数无法修改普通成员变量的值,只能获取值,==只能读不能写==(通俗的讲,把一个函数设置成为常函数,就是不想去设置值,只是区获取值)
  • 如果一个成员函数只是获取成员变量的值,可以将这个函数设置为常函数
  • 如果要对指定的成员变量执行写操作,则需要使用mutable修饰这个成员变量,mutable 关键字修饰的成员变量可以在常成员函数中被修改
  • 常成员函数可以重载 (常函数版本和非常函数版本可以构成重载关系)
  • 非常对象,优先调用普通的成员函数,如果没有,调用常函数版本

1.2 常对象

  • 使用const修饰的对象称之为常对象
  • 常对象是可以正常调用构造函数
  • ==常对象无法操作普通成员函数,只能调用常函数==
  • 常对象只能操作公有的被mutable修饰的成员变量
#include <iostream>

using namespace std;

class Myclass
{
public:
    Myclass(){cout << "无参构造函数" << endl;}
    Myclass(int a, int b, int c):a(a),b(b),c(c)
    {
        cout << "有参构造函数" << endl;
    }

    void ConstFun()const
    {
        //this->a = 100;
        this->b = 200;
        //this->c = 300;
        this->d = 400;

        cout << this->a << ", ";
        cout << this->b << ", ";
        cout << this->c << ", ";
        cout << this->d << endl;
    }

    void printMsg()
    {
        cout << this->a << ", ";
        cout << this->b << ", ";
        cout << this->c << ", ";
        cout << this->d << endl;
    }

    int a = 0;
    mutable int b = 0;
private:
    int c = 0;
    mutable int d = 0;
};

void test1()
{
    Myclass m;
    m.ConstFun();
}

void test2()
{
    const Myclass m1;
    const Myclass m2(333, 666, 888);
    //m2.printMsg();
    m2.ConstFun();
    
    //m2.a = 123;
    m2.b = 234;
    //m2.c = 345;
    //m2.d = 456;
}

int main()
{
    test2();

    return 0;
}

二、静态成员变量和静态成员函数

2.1 静态成员函数

  • 静态成员函数就是用static修饰的成员函数
  • ==静态成员函数内没有this指针==,所以只能访问静态成员变量,不能访问普通成员变量
  • 静态成员函数内无法操作普通成员变量
  • 静态成员函数只能操作静态成员变量
  • 静态成员函数属于类,而不属于对象,所以==可以通过类名直接调用==,普通成员函数无法通过类直接调用。
  • 静态成员函数属于整个类
Team t1("张三");
t1.show_flag();//静态成员函数的访问方法1 :通过类对象进行访问
Team::show_flag();//静态成员函数的访问方法2 :通过类名直接访问

2.2 静态成员变量

  • 静态成员变量操作之前必须要在**==类外初始化==**,否则报错

    初始化格式:eg:int Myclass::a = 0;

  • 静态成员变量不属于某一个对象,而是属于类,所以操作静态成员变量,一般通过类名结合域解析符来操作

  • 静态成员变量属于整个类,并不是属于某个类对象,被所有的类对象共享,一个类对象对其进行了修改,所有的类对象中该成员变量都会变成新的值

#include <iostream>

using namespace std;

class Myclass{
public:
    Myclass()
    {
        cout << "无参构造函数" << endl;
    }
    Myclass(int a, int b)
    {
        cout << "有参构造函数" << endl;
        this->a = a;
        this->b = b;
    }

    void printMsg()
    {
        cout << this->a << ", " << this->b << endl;
    }

    //静态成员函数
    //  静态成员函数就是用static修饰的成员函数
    //  静态成员函数内没有this指针
    //  静态成员函数内无法操作普通成员变量
    //  静态成员函数只能操作静态成员变量
    //  静态成员函数属于类,而不属于对象,所以可以通过类名直接调用
    static void StaticFun()
    {
        Myclass::a = 100;
        Myclass::b = 200;
        //c = 300;
        //d = 400;
        cout << Myclass::a << ", " << Myclass::b << endl;
        //cout << c << ", " << d << endl;
    }

    //静态成员变量
    //  静态成员变量操作之前必须要在类外初始化,否则报错
    //  静态成员变量不属于某一个对象,而是属于类,所以操作静态成员变量,一般通过类名结合域解析符来操作
    static int a;
    int c;
private:
    static int b;
    int d;
};

//静态成员变量都要在类外初始化
int Myclass::a = 0;
int Myclass::b = 0;

void test1()
{
    Myclass m1;
    Myclass m2(100, 200);
    m2.printMsg();

    m2.a = 888;
    cout << "m2.a = " << m2.a << endl;

    Myclass m3;
    cout << "m3.a = " << m3.a << endl;

    cout << Myclass::a << endl;
    Myclass::a = 111;

    cout << "m2.a = " << m2.a << endl;
}

void test2()
{
    Myclass m1;
    m1.StaticFun();
    
    //静态成员函数属于类,所以可以让类直接调用
    Myclass::StaticFun();
    //普通成员函数无法通过类直接调用
    //Myclass::printMsg();
}

int main()
{
    test2();

    return 0;
}

📝练习:判断当前类实例化了多少个对象

#include <iostream>

using namespace std;

class Myclass{
public:
    Myclass()
    {
        Myclass::num++;
    }

    ~Myclass()
    {
        Myclass::num--;
    }

    Myclass(const Myclass &obj)
    {
        Myclass::num++;
    }

    static int num;

};

int Myclass::num = 0;

void test1()
{
    Myclass m1;
    Myclass m2;
    cout << __LINE__ << "行的对象的个数是:" << Myclass::num << endl;

    //代码块:拥有独立的空间,执行结束后空间释放,
    //代码块前面的程序的数据可以在内部操作
    {
        Myclass m3;
        Myclass m4;
        cout << __LINE__ << "行的对象的个数是:" << Myclass::num << endl;
    }
    cout << __LINE__ << "行的对象的个数是:" << Myclass::num << endl;

    Myclass m5 = m1;
    cout << __LINE__ << "行的对象的个数是:" << Myclass::num << endl;
}

int main()
{
    test1();
    cout << __LINE__ << "行的对象的个数是:" << Myclass::num << endl;

    Myclass m6;
    Myclass m7;
    cout << __LINE__ << "行的对象的个数是:" << Myclass::num << endl;

    return 0;
}

执行结果:

图片.png

三、友元

友元:是另外一种操作类内私有成员的方法

分类:

  • 友元函数(友元全局函数)
  • 友元类
  • 友元成员(友元成员函数)

📣注意:

  • 1.友元不具有双向性;//A是B的朋友,B不一定是A的朋友
  • 2.友元不具有传递性;//A是B的朋友,B是C的朋友,A不一定是C的朋友
  • 3.友元关系不能被继承; //父类的朋友不一定是子类的朋友

7.1 友元函数

将一个全局函数设置为友元,称之为友元函数,友元函数内部可以对类中的所有成员进行操作。

友元函数:

  • 将全局函数在类中使用friend声明,那么这个函数为友元函数
  • 友元函数可以操作类中的任意成员
#include <iostream>

using namespace std;

class Dc21071{
   
    friend void zhangsan();
public:
    string name;
    char sex;
    string phone;
private:
    string sid;
    string address;
    bool bgfriend;
};

void zhangsan()
{
    Dc21071 xiaoli;
    xiaoli.name = "小丽";
    xiaoli.sex = 'M';
    xiaoli.phone = "18888888888";

    xiaoli.sid = "11019999999999";
    xiaoli.address = "北京明园大学";
    xiaoli.bgfriend = true;

    cout << xiaoli.name << ", ";
    cout << xiaoli.sex << ", ";
    cout << xiaoli.phone << ", ";
    cout << xiaoli.sid << ", ";
    cout << xiaoli.address << ", ";
    cout << xiaoli.bgfriend << endl;
}

int main()
{
    zhangsan();
    return 0;
}

7.2 友元类

友元类:

  • 将类a作为类b的友元,将a称之为友元类
  • 类a中的所有成员函数内都可以操作类b中的任意成员
#include <iostream>

using namespace std;

class Dc21071{
   
    friend class banzhuren;
public:
    string name;
    char sex;
    string phone;
private:
    string sid;
    string address;
    bool bgfriend;
};

class banzhuren{
public:
    void xiaoli()
    {
        Dc21071 xiaoli;
        xiaoli.name = "小丽";
        xiaoli.sex = 'M';
        xiaoli.phone = "18888888888";

        xiaoli.sid = "11019999999999";
        xiaoli.address = "北京明园大学";
        xiaoli.bgfriend = true;

        cout << xiaoli.name << ", ";
        cout << xiaoli.sex << ", ";
        cout << xiaoli.phone << ", ";
        cout << xiaoli.sid << ", ";
        cout << xiaoli.address << ", ";
        cout << xiaoli.bgfriend << endl;
    }

    void wangli()
    {
        Dc21071 xiaoli;
        xiaoli.name = "小丽";
        xiaoli.sex = 'M';
        xiaoli.phone = "18888888888";

        xiaoli.sid = "11019999999999";
        xiaoli.address = "北京明园大学";
        xiaoli.bgfriend = true;

        cout << xiaoli.name << ", ";
        cout << xiaoli.sex << ", ";
        cout << xiaoli.phone << ", ";
        cout << xiaoli.sid << ", ";
        cout << xiaoli.address << ", ";
        cout << xiaoli.bgfriend << endl;
    }
};

int main()
{
    banzhuren shanshan;
    shanshan.xiaoli();
    shanshan.wangli();
    
//    banzhuren jiaojiao;
//    jiaojiao.zhangli.address = "北京";
    return 0;
}

7.3 友元成员

友元成员:

  • 将一个类的某一个成员函数作为另一个类的友元,称之为友元成员
  • 这个友元成员函数内部可以操作那个类的任意成员,但是其他成员函数不能操作

必须按照顺序设置,不然会报错:

  • 第一步:声明要设置友元的类
  • 第二步:先定义要设置的友元成员所在的类
  • 第三步:声明要设置友元成员的成员函数
  • 第四步:定义要设置友元的类
  • 第五步:声明要设置友元成员的成员函数
  • 第六步:友元成员函数类外实现
#include <iostream>

using namespace std;

//第一步:声明要设置友元的类
class Dc21071;

//第二步:先定义要设置的友元成员所在的类
class banzhuren{
public:
//第三步:声明要设置友元成员的成员函数
	void shanshan();
};

//第四步:定义要设置友元的类
class Dc21071{
//第五步:声明要设置友元成员的成员函数
	friend void banzhuren::shanshan();
public:
    string name;
    char sex;
    string phone;
private:
    string sid;
    string address;
    bool bgfriend;
};

//第六步:友元成员函数类外实现
void banzhuren::shanshan()
{
    Dc21071 xiaoli;
    xiaoli.name = "小丽";
    xiaoli.sex = 'M';
    xiaoli.phone = "18888888888";

    xiaoli.sid = "11019999999999";
    xiaoli.address = "北京明园大学";
    xiaoli.bgfriend = true;

    cout << xiaoli.name << ", ";
    cout << xiaoli.sex << ", ";
    cout << xiaoli.phone << ", ";
    cout << xiaoli.sid << ", ";
    cout << xiaoli.address << ", ";
    cout << xiaoli.bgfriend << endl;
}

int main()
{
    banzhuren b;
    b.shanshan();
    //b.jiaojiao();

    return 0;
}