Day41、静态成员变量、静态成员函数、单例模式、成员/成员函数指针、操作符重载、友元函数

一、            静态成员

1、 静态成员变量

class 类名{

       static数据类型 数据明;//声明

};

数据类型 类名::变量名=初值;//定义和初始化

1) 静态成员变量不属于对象

2) 不能在构造函数中被定义和初始化,需要在类的外部单独地定义及初始化

3) 可以通过类名直接访问,也可以通过对象访问

4) 静态成员变量存放在全局区(代码段和BS,普通成员变量在栈区。

5) 静态成员使用受到访问控制属性的约束

  1#include<iostream>

  2using namespace std;

  3class A{

  4public: 

 5     int m_data;

  5// pvivate:

 6     static int s_data;

  7};

  8int A::s_data=100;

  9int main(void){

 10     Aa;

 11    cout<<sizeof(a)<<endl;//4

 12    cout<<A::s_data<<endl;//100

 13    cout<<a.s_data<<endl;//也可以通过对象访问 

 14 }

2、 静态成员函数

1) 可以通过类名直接访问,也可以通过对象访问

2) 静态成员函数没有this指针,因此也没有const属性

3) 和普通成员函数一样受访问控制限定符的约束

4) 静态成员函数存放在全局区(代码段和BS

 

  1#include<iostream>

  2using namespace std;

  3class A{

  4public:

  5//private:

 6     static voidfunc(void)/*const*/{

 7         cout<<"静态成员函数"<<endl;

 8     }

  9};

 10int main(void){

 11    A::func();//作用域

 12    return 0;

 13 }

3、 静态成员函数只能访问静态成员;非静态成员函数既能访问静态成员,也能访问非静态成员(因为静态成员函数没有this指针)

  1#include<iostream>

  2using namespace std;

  3class A{

  4public:

 5     static void func(void)/*const*/{

 6         cout<<"静态成员函数"<<endl;

 7        cout<<s_data<<endl;

 8        //cout<<m_data<<endl;

 9         //静态成员函数只能访问静态成员

 10     }

 11    void func2(void){

 12        cout<<"非静态成员函数"<<endl;

 13        cout<<s_data<<endl;

 14        cout<<m_data<<endl;

 15        //非静态成员函数既能访问静态成员,也能访问非静态成员

 16     }

 17    static int s_data;

 18    int m_data;

 19};

 20int A::s_data=100;

 21int main(void){

 22     Aa;

 23    a.m_data=200;

24     a.func();//A::func()

 25    a.func2();

 26    return 0;

 27 }

tarena@tarena-virtual-machine:~/day41$./a.out

静态成员函数

100

非静态成员函数

100

200

4、 单例模式

单例:只允许存在唯一的对象实例

1) 禁止在类的外部创建对象:私有化构造函数

2) 类自己内部维护唯一的对象:静态成员变量

3) 提供访问该对象的方法:静态成员函数

具体实现方式:

-à饿汉式:无论用与不用单例对象,程序启动即创建

  1#include<iostream>

  2using namespace std;

  3class A{

  4public:

 5     static A&getInstance(void){

 6         return s_instance;

 7     }

  8private:

 9     A(int data=0):m_data(data){}

 10//  A(const A& that);//不写拷贝构造函数,编译器则提供一个缺省的公有构造函数

 11    int m_data;

 12    static A s_instance;//唯一对象

 13};

 14 AA::s_instance(1234);

 15int main(void){

 16//  A a;error

 17//  A *pa=new A(4321);error

 18    A& a1=A::getInstance();

 19    A& a2=A::getInstance();

 20    cout<<"&a1="<<&a1<<endl;

 21    cout<<"&a2="<<&a1<<endl;

 22    return 0;

 23 }

 

-à懒汉式:单例对象用时再创建,不用了即销毁

  1#include<iostream>

  2using namespace std;

  3class A{

  4public:

 5     static A&getInstance(void){

 6         if(!s_instance){   //保证只new一个空间

 7             s_instance=newA(1234);

 8         }

 9         ++s_counter;

 10         return *s_instance;

 11     }

 12        void release(void){

 13            if(s_counter&&--s_counter==0){//判断是否最后一个对象在使用

 14            delete this;//自销毁

 15            }

 16        }

 17private:

 18    A(int data=0):m_data(data){

 19         cout<<"A::A()"<<endl;

 20     }

 21    ~A(void){

 22        cout<<"A::~A()"<<endl;

 23        s_instance=NULL;

24     }

 25    A(const A& that);

 26    int m_data;

 27    static A* s_instance;//唯一对象

 28    static int s_counter;

 29};

 30A* A::s_instance=NULL;//初始化

 31int A::s_counter=0;//记录单例对象别名数目

 32int main(void){

 33//  A a;error

 34//  A *pa=new A(4321);error

 35    A& a1=A::getInstance();

 36    A& a2=A::getInstance();

 37    A& a3=A::getInstance();

 38    cout<<"&a1="<<&a1<<endl;

 39    cout<<"&a2="<<&a1<<endl;

 40    cout<<"&a3="<<&a1<<endl;

 41    a1.release();

 42    a2.release();

 43    a3.release();//delete

 44    return 0;

 45 }

tarena@tarena-virtual-machine:~/day41$./a.out

A::A()

&a1=0x8c88008

&a2=0x8c88008

&a3=0x8c88008

A::~A()

 

二、            成员指针(了解)

1、成员变量指针

1)定义:
类型  类名::*成员指针变量名=&类名::成员变量

例:

class student{

       string m_name;

};

//成员变量指针、

string student::*pname=&student::m_name’

student s;

string*p=&s.name;//普通指针

2)使用:

对象 .* 成员指针变量名;

“.*”成员指针解引用运算符

 

对象指针->*成员指针变量名

“->*”间接成员指针解引用运算符

  1 #include<iostream>

  2 using namespace std;

  3 class Student{

  4 public:

  5    Student(const string& name):m_name(name){}

  6    string m_name;

  7 };

  8 int main(void){

  9    //成员变量指针的本质就是类中特定成员还在对象中的相对地址

 10    string Student::*pname=&Student::m_name;

 11     Student s1("张飞");

 12    Student s2("张二");

 13    cout<<s1.*pname<<endl;;

 14    Student* ps=&s2;

 15    cout<<ps->*pname<<endl;

 16 }

2、成员函数指针

1)  定义

返回类型 (*类名::成员函数指针)(形参表)=&类名::成员函数名

2)  使用

(对象.*成员函数指针)(实参表)

(对象指针->*成员函数指针)(实参表)

  1 #include<iostream>

  2 using namespace std;

  3 class Student{

  4 public:

  5    Student(const string& name):m_name(name){}

  6    void who(){

  7        cout<<m_name<<endl;

  8     }

  9 private:

 10    string m_name;

 11 };

 12 int main(void){

 13    void(Student::*pwho)(void)=&Student::who;

 14    Student s1("张三");

 15    Student s2("李四");

 16    (s1.*pwho)();

 17    Student* ps=&s2;

 18    (ps->*pwho)();

 19    //s1.who();

 20    //s2.who();

 21    return 0;

 22 }

张三

李四

张三

李四

三、            操作符重载

例:复数:实部+虚部i

  1 #include<iostream>

  2 using namespace std;

  3 class Complex{

  4 public:

  5    Complex(int r,int i):m_r(r),m_i(i){}

  6    void print(void)const{

  7        cout<<m_r<<'+'<<m_i<<'i'<<endl;

  8    }/*

  9    Complex add(Complex c){

 10        return Complex(m_r+c.m_r,m_i+c.m_i);//返回构造匿名对象

 11    }*/

 12    Complex operator+(Complex c){

 13        return Complex(m_r+c.m_r,m_i+c.m_i);//返回构造匿名对象

 14     }

 15 private:

 16    int m_r;//实部

 17    int m_i;//虚部

 18 };

 19 int main(void){

 20    Complex c1(1,2);

 21    Complex c2(3,4);

 22    c1.print();

 23    c2.print();

24    //c1+c2;error

 25 // Complex c3=c1.add(c2);

 26    Complex c3=c1+c2;//c1.operator+(c2)

 27    c3.print();//4+6i;    

 28    return 0;

 29 }

1+2i

3+4i

4+6i

1、双目操作符的重载:L#R

1.1   运算类双目操作符

----à左右操作数既可以是左值也可以是右值(a+10;a是左操作数,10是右操作数)

---à表达式的结果是右值

1)  成员函数形式

L#R==>L.operator#(R)成员函数调用的形式

  1 #include<iostream>

  2 using namespace std;

  3 class Complex{

  4 public:

  5    Complex(int r,int i):m_r(r),m_i(i){}

  6    void print(void)const{

  7        cout<<m_r<<'+'<<m_i<<'i'<<endl;

  8    }/*

  9    Complex add(Complex c){

 10        return Complex(m_r+c.m_r,m_i+c.m_i);//返回构造匿名对象

 11    }*/

 12    /*从左到右三个const

 13     *1)返回右值

 14     *2)常引用:支持常右操作数

 15     *3)常函数:支持常左操作数(常对象只能调用常函数)  */

 16    const Complex operator+(const Complex& c)const{

 17        return Complex(m_r+c.m_r,m_i+c.m_i);//返回构造匿名对象

 18     }

 19 private:

 20    int m_r;//实部

 21    int m_i;//虚部

 22 };

 23 int main(void){

24    const Complex c1(1,2);

 25    const Complex c2(3,4);

 26    c1.print();

 27    c2.print();

 28    //c1+c2;error

 29 // Complex c3=c1.add(c2);

 30    Complex c3=c1+c2;//c1.operator+(c2)

 31    c3.print();//4+6i;    

 32 //   (c1+c2)=c3;    error

 33    return 0;

 34 }

2)全局函数形式

L#R==》::operator#(L,R)全局函数调用形式,函数返回的结果就是表达式的结果

注:friend关键字

通过friend关键字,可以把一个全局函数声明为某个类的友元,友元函数可以访问类中任何成员。

#include<iostream>

using namespace std;

class Complex{

public:

    Complex(int r,int i):m_r(r),m_i(i){}

    void print(void)const{

       cout<<m_r<<'+'<<m_i<<'i'<<endl;

    }/*

    Complex add(Complex c){

        return Complex(m_r+c.m_r,m_i+c.m_i);//返回构造匿名对象

    }*/

    /*从左到右三个const

     *1)返回右值 c3

     *2)常引用:支持常右操作数 c2

     *3)常函数:支持常左操作数(常对象只能调用常函数) c1

       Complex c3=c1+c2;//c1.operator+(c2)        */

    const Complex operator+(const Complex&c)const{

        return Complex(m_r+c.m_r,m_i+c.m_i);//返回构造匿名对象

    }

private:

    int m_r;//实部

    int m_i;//虚部

    //friend声明函数可以访问类中任何成员

    friend const Complex operator-(constComplex& l,const Complex& r);

};

const Complexoperator-(const Complex& l,const Complex& r){

    return Complex(l.m_r-r.m_r,l.m_i-r.m_i);

}

int main(void){

    const Complex c1(1,2);

    const Complex c2(3,4);

    c1.print();

    c2.print();

    //c1+c2;error

//  Complex c3=c1.add(c2);

    Complex c3=c1+c2;//c1.operator+(c2)

    c3.print();//i4+6i;    

//    (c1+c2)=c3;    error

    Complex c4=c1+c2+c3;

    c4.print();//8+12i

    c4=c3-c1;//operator(c3,c1)

    c4.print();//3+4i

    return 0;

}

1.2   赋值类的双目操作符

--à左操作数必须是左值,不能是常量

--à右操作既可以是左值,也可以是右值

--à表达式的结果是左值,就是左操作自身

1)成员函数形式

L#R==>L.operator#R

2)全局函数形式

L#R==>::operator#(L,R)

  1 #include<iostream>

  2 using namespace std;

  3 class Complex{

  4 public:

  5    Complex(int r,int i):m_r(r),m_i(i){}

  6    void print(void)const{

  7        cout<<m_r<<'+'<<m_i<<'i'<<endl;

  8     }

  9    Complex& operator+=(const Complex& c){

 10        m_r+=c.m_r;

 11        m_i+=c.m_i;

 12        return *this;

 13     }

 14 private:

 15    int m_r;//实部

 16    int m_i;//虚部

 17    //友元函数可以定义在类的内部,但不属于类,还是一个全局函数,也没有this指

    针

 18    friend Complex& operator-=(Complex& l,const Complex& r){

 19        l.m_r-=r.m_r;

 20        l.m_i-=r.m_i;

 21        return l;

 22     }

23 };

 24 int main(void){

 25    Complex c1(1,2);

 26    Complex c2(3,4);

 27    c1+=c2;//c1.operator+=(c2);

 28    c1.print();//4+6i

 29    c1-=c2;//::operator-=(c1,c2);

 30    c1.print();//1+2i

 31    return 0;

 32 }

2、插入和提取操作符重载:<<   >>

cout <<a ;

cout<<b<<endl;

#include<iostream>

ostream cout;

friend ostream&operator<<(ostream& os,const RIGHT& right) {..}

举例:

  1 #include<iostream>

  2 using namespace std;

  3 class Complex{

  4 public:

  5    Complex(int r,int i):m_r(r),m_i(i){}

  6 /*   void print(void)const{

  7        cout<<m_r<<'+'<<m_i<<'i'<<endl;

  8    }*/

  9    //输出操作符<<重载是固定模版

 10     friendostream& operator<<(ostream& os,const Complex& c){

 11        os<<c.m_r<<'+'<<c.m_i<<'i';

 12     }

 13 private:

 14    int m_r;//实部

 15    int m_i;//虚部

 16

 17 };

 18 int main(void){

 19    Complex c1(1,2);

 20    Complex c2(3,4);

 21    //operator<<(cout,c1)

 22    //cout<<endl

 23    cout<<c1<<endl;  //1+2i

 24    cout<<c2<<endl;  //3+4i

 25    return 0;

 26 }

 

 

练习:

实现3*3矩阵类,支持如下操作符:

+  - +=   -=

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值