【C++】4. 静态成员,单例模式,this,常函数,友元

本文详细介绍了C++中的静态成员变量和静态成员函数,强调了它们在内存中的存储位置和访问方式。同时,讲解了静态成员在实现单例模式中的应用,展示了如何确保类的唯一实例。此外,还探讨了this指针的作用、链式编程、空指针调用成员函数、常函数与常对象的概念,以及友元在访问私有成员时的重要性。
摘要由CSDN通过智能技术生成

1.静态成员变量

**静态成员变量必须在类中声明,在类外定义**
  • 在一个类中,若将一个成员变量声明为static,这种成员称为静态成员变量.
  • 静态变量,是在编译阶段就分配了空间->对象还没有创建时,就已经分配了空间.
  • 不管这个类创建了多少个对象,静态成员只有一个拷贝,这个拷贝被所有属于这个类的对象共享

(1)public下

  1. 通过对象访问属性
    不允许在类内初始化; 要在类外初始化,且要声明; static变量的值是最后修改的那一份!
class Person{  
public:  
    static int Age;//[不允许在类内初始化]   
};  
int Person::Age=22;//[类外初始化]  
void test01(){  
    Person p1;  
    p1.Age=1;  //[最后打印p2.age]
    Person p2;  
    p2.Age=10;  //[最后打印p2.age]
    cout<<"p1的年龄是"<<p1.Age<<endl<<"p2的年龄是"<<p2.Age<<endl;  
}
  1. 通过类名访问static属性(一般采用这种方法)
    cout<<"static变量age的值是"<<Person::Age<<endl;

(2)private下

  • 定义时:
private:  
    static int weight;//私有权限->在类外不能访问
  • 类外初始化时:
    int Person::weight=90; //类外初始化能成功.仅限这里能成功.
  • 调用时:
    • 调用对象的get方法:cout<<p1.getWeight()<<endl;这样能成功!
    • 通过类名访问:cout<<Person::weigth<<endl;这样会失败!

2.静态成员函数

静态成员函数主要为了访问静态变量,但是,[不能访问普通成员变量!]。
静态成员函数的意义,不在于信息共享/数据沟通,而在于管理静态数据成员,完成对静态数据成员的封装。
普通成员函数可访问静态成员变量、也可以访问非经常成员变量.
  1. 静态成员函数的写法
static void func(int iAge){  
    Age=iAge;  
    cout<<"func调用了"<<endl;  
}
  1. 静态成员函数的调用
p2.func(40);  
p1.func(55);  //通过对象调用
Person::func(60);  //通过类名调用

3.静态成员实现单例模式

单例模式:在系统中某个类的对象只能存在一个

(1)概述

  • 它提供一个静态static的getInstance() 工厂方法,让客户可以访问它的唯一实例.
  • 为了防止在外部对其实例化,将其默认构造函数和拷贝构造函数设计为私有private.
  • 在单例类内部定义了一个Singleton类型的静态static对象,作为外部共享的唯一实例.

(2)案例

①主席案例

  • 类的写法:
    • 只有getInstance()方法是public的
    • 静态化这唯一的singleMan对象,在类内声明,类外初始化!
    • 构造函数和拷贝构造函数都要私有化!
class ChairMan{  
public:  
    static ChairMan* getInstance(){//通过get方法来访问private变量singleMan  
        return singleMan;  
    }
private:  
    static ChairMan * singleMan;//维护这唯一对象的指针->类内声明!  
    ChairMan(){ //构造函数私有化 ;
        cout<<"创建国家主席"<<endl;  
    }    
    ChairMan(const ChairMan * cm){  
	  //拷贝构造函数私有化;
    }  
};	
  • 类外初始化singleMan对象
    ChairMan * ChairMan::singleMan=new ChairMan;//类外初始化!
  • 调用的写法:
    ChairMan * cm1=ChairMan::getInstance();

②打印机案例

 题目:用单例模式模拟公司员工使用打印机场景,打印机可以打印员工要输出的内容,并且可以累积打印机使用次数。
  • 类内的写法:
class Printer{  
public:  
    static Printer * getInstance(){  
        return SinglePrinter;  
    }    
    void printText(string text){  
        cout<<"打印机打印了"<<text<<endl;  
        count++;  
        cout<<count<<endl;  
    }
private:    
    int count=0;  
    static Printer * SinglePrinter ;  
    Printer(){  
        cout<<"使用了打印机哟"<<endl;  
    }    
    Printer(const Printer * iprinter){  
        cout<<"使用了拷贝构造函数的打印机"<<endl;  
    }
};
  • 类外的写法:
    Printer * Printer::SinglePrinter=new Printer;
  • 调用的写法:
void test(){  
    Printer * p1=Printer::getInstance();  
    p1->printText("一张A4纸");  
    Printer * p2=Printer::getInstance();  
    p2->printText("两份试卷");  
}

4. 成员属性和函数的存储

c++实现了封装,那么成员属性和成员函数是如何存储的呢?
答:成员属性和成员函数是[分开存储]的.
  • c++中的非静态数据属性直接内含在对象中.
  • 静态成员属性,不在对象上.
    - 成员函数(静态和非静态都)内含在class声明之内,但不出现在对象中.每一个非内联成员函数(non-inline member function)只会诞生一份函数实例.

5. this指针

上节提到的成员函数只会诞生一份实例,那不同对象调用同一个函数时是怎么区分的呢?
答:使用this指针,指向被调用的成员函数所属的对象.
  • 所有的非静态成员函数void func(Person * this),其中Person * this是编译器默认添加的指针,我们看不到.
  • this永远指向当前对象!
  • this用于解决命名冲突(形参和成员属性同名)
  • 在类的非静态成员函数中返回对象本身,使用return *this

6. 链式编程

Person& plus(Person & p){  
    this->age+=p.age;  
    return *this;//*this指向本体  
}

p2.plus(p1).plus(p1).plus(p1).plus(p1)...;

  1. 函数返回Person&!
  2. return *this!
  3. 无限调用

7. 空指针访问成员函数

Person *p=NULL;*,则p可以调用[未使用到this]的成员函数.

8.常函数与常对象

利用const修饰成员函数

(1)const修饰成员函数->常函数

  • 写法:void func() const{}
void showPerson() const{  
    this->a=11;//这样就会报错了,因为用const修饰后不允许再修改成员属性
}
  • 常函数的原理:修饰的是this指针->const Type * const this;
  • 有一些比较特殊的变量希望能够在常函数中进行修改:则加上mutable关键字
    mutable int b;

(2)const修饰对象->常对象

  • 写法:const ClassName className;
  • 常对象初始化了后不允许修改属性:
const Person p2;  
p2.a=11;//会报错,因为常对象不允许修改属性!
  • 常对象不可以调用普通成员函数:
    ![[Pasted image 20221006144049.png]]
  • 常对象可以调用常函数.

9.友元friend

类的私有属性一般无法在作用域之外访问,但有时候需要在类的外部访问类的私有属性,怎么做到呢?
答:使用友元函数.
       友元函数是一种特权函数,c++允许这个特权函数访问私有成员。
 	   程序员可以把一个全局函数、成员函数、甚至整个类声明为友元。

①全局函数作友元函数

  • 类内声明友元函数:
    //让全局中的好基友函数变成我的好朋友->使用友元函数
    friend void goodGay(Building * building);
  • 全局中定义函数方法:
void goodGay(Building * building){//全局的好基友函数  
    cout<<"你的朋友在访问:"<<building->SittingRoom<<endl;  
    cout<<"你的朋友在访问:"<<building->BedRoom<<endl;//这个BedRoom是private变量  
}
  • 调用写法:
    goodGay(&building1);

②成员函数作友元函数

friend void goodGay::func();

③整个类作友元

friend class goodGay;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值