Day_05 特殊成员(const 、static)与友元

1.const

(1).const成员数据

        const修饰词,可以修饰成员数据,也可以修饰成员函数。修饰成员数据时,表示成员数据不能更改。且成员函数只能通过初始化列表来赋值(或者在定义数据成员时就给它赋初始值)。

class MM{
public:
    MM(){string name,int age}:name(name),age(age){
            
    }
    void print(){
        //age=22;  错误 一旦通过初始化参数列表之后就不能再修改
     }
protected:
    const int age = 10;
    string name; 
}

(2)const成员函数

       const 成员函数可以使用类中的所有成员变量,但是不能修改它们的值,这种措施主要还是为了保护数据而设置的。const 成员函数也称为常成员函数。

        常成员函数可以与成员函数的函数名相同,调用函数方法时,优先调用普通成员函数,普通函数找不到,才会调用常成员函数。

class MM{
public:
    MM(){string name,int age}:name(name),age(age){
            
    }
    void print(){
        //age=22;  错误 一旦通过初始化参数列表之后就不能再修改
     }
    //常成员函数
    void print() const{
        //string name = "xx" 错误写法
        cout<<name<<endl;
    }
protected:
    const int age = 10;
    string name; 
}

(3)const常对象

        和普通定义对象一样,只不过普通定义对象前面加个cosnt修饰。但和普通对象不同,常对象只能调用常成员函数。无法调用普通成员函数,普通对象既能调用普通成员函数,又能调用常成员函数。但是,当常成员函数和普通成员函数重名时,普通对象无法强制调用常成员函数。

const MM m1;    //定义一个无参常对象

小结:

+ const数据成员
  + const类型变量是不可以修改,只读模式
  + 必须采用初始化参数列表方式进行初始化


+ const成员函数
  + 写法上, const写在函数后面
  + 常成员函数是不能够修改数据成员,只读数据成员
  + 常成员函数可以与普通函数同时存在
            + 普通函数和常成员函数相同时,普通对象优先调用普通函数
            + 普通对象可以调用常成员函数


+ const对象: const修饰的对象
  + 常对象只能调用常成员函数

2.static

        static成员是不属于对象,是属于类的,意味着是所有对象共有的,调用可以不需要对象,当然你可以用对象调用(前提是在public下定义的静态数据成员),即静态数据成员仍然受权限限定。

(1).static成员数据

        static定义的成员数据只能在类外初始化(定义的时候赋值也是错误的),类外初始化的时候不需要加static,但需要加上类名限定。

class MM{
public:
    //错误写法,静态数据成员并不能通过初始化参数列表来初始化
    //MM(string name,int age):name(name),age(age){};
protected:
static string name;
static int age;
}

//静态成员数据必须在类外初始化,不能在类内初始化
int MM::age=20;
string MM::name="xxx";

         让我们来看一个实例,更好的理解静态成员变量是类中公有的这个概念。

class MM{
public:
	//不能使用初始化参数列表的方式来初始化static类型的变量
	MM(string name=" ") :name(name){
		num++;
	}

	//静态成员函数
	static void printMM();

protected:
	string name;
public:
	static int num;
};

int MM::num=0;

int main(){
    MM m1("xx");
    cout<<MM::num<<endl;      //num=1
    MM m2[3];
    cout<<MM::num<<endl;      //num=4
    MM* m3=new MM("zz");        
    cout<<m3.num<<endl;       //num=5
    return 0;
}

        代码中,MM类中static数据成员num 会随着构造函数的调用而增加。每调用一次构造函数,就会num+1,到最后调用了5次构造函数 num=5。

(2).static成员函数

        在成员函数前加上一个static修饰即可。和静态成员数据一样,在类外实现的时候不需要static,只要加上类名限定就行。

class MM{
public:
	MM(string name=" ") :name(name){
		num++;
	}
	//静态成员函数
	static void printMM();
protected:
	string name;
public:
	static int num;
};

//类外实现静态成员函数 需要类名限定
void MM::printMM(){
    cout<<"静态成员函数"<<endl;
}

        但是需要注意的是静态成员函数调用非静态成员数据时要指定对象。很容易理解(静态成员函数是属于类的,是每个对象共有的,而对于非静态成员数据来说,每个对象对应的值都不相同。不指定对象,静态成员函数不知道去访问哪个。)

3.友元

       友元只是提供一个场所,赋予对象具有打破类的权限定(无视权限)。函数前置加friend,需要注意:友元函数不属于类(不是成员函数),不可以直接访问类中的成员数据。但是在友元函数中,对象可以直接访问类中的成员数据,不受权限限定。

(1).普通友元函数

        成员函数在调用时会隐式地增加 this 指针,指向调用它的对象,从而使用该对象的成员;而 show() 是非成员函数,没有 this 指针,编译器不知道使用哪个对象的成员,要想明确这一点,就必须通过参数传递对象(可以直接传递对象,也可以传递对象指针或对象引用),并在访问成员时指明对象。

class MM{
public:
    MM(){string name,int age}:name(name),age(age){
            
   }
    //友元函数
   friend void print(MM& mm){
      //下面是错误写法
        cout<<name<<" "<<age<<endl; 错误写法 友元函数不属于类,不能直接访问成员数据
        //需要传入对象或者对象的引用
        cout<<mm.name<<" "<<mm.age<<endl;    
   }
protected:
    int age = 10;
    string name; 
}
int main(){
    MM m(" ",22);
    //调用友元函数直接访问成员数据
    print(mm);
    return 0;
}

        友元函数不属于类,所以友元函数在类中定义类外实现时,不需要加类名限定,也不需要加friend修饰。

(2).以另一个类的成员函数为友元函数(很容易出错)

        例:以B类中的成员函数为A的友元函数:首先要先写B类,并声明成员函数。然后写A类,并声明友元函数,接着在类外实现B类的成员函数。这个顺序不能修改。

//以B类的成员函数为A类的友元函数示例
class B{
public:
    void printA();
protected:
}

class A{
public:
    //申明友元函数
   friend void B::printA();
protected:
    string name="A";
}
//成员函数实现
void B::printA(){
    A a;
    cout << a.name << endl;
}

(3).友元类

        在A类中声明B类是A的友元类,则B中所有的成员函数都是A的友元函数,即B中的成员函数中若有A类的对象,则该对象可以打破类的访问限制

#include <iostream>
using namespace std;
class MM 
{    
    //申明友元类 则GG中所有的成员函数在访问MM类的对象时 都能打破MM类的限制
	friend class GG;
public:
	MM(string name, int age) :name(name), age(age) {}
protected:
	string name;
	int age;
};
class GG 
{
public:
	void print() 
	{
		MM mm("mm", 18);
		cout << mm.name << "\t" << mm.age << endl;
	}
	void printMM(MM& mm) 
	{
		cout << mm.name << "\t" << mm.age << endl;
	}
	MM& returnMM(MM& mm) 
	{
		return mm;
	}
protected:
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值