C++:内嵌类、静态成员变量和函数、单例模式、友元函数和友元类

来源:互联网 发布:163邮箱大师 mac 编辑:程序博客网 时间:2024/04/29 18:27
一、内嵌类
1. 什么是内嵌类:
内嵌类是指,一个类定义在另一个类的内部。
2. 类内声明,类外实现的方法:
返回类型 外部类::内嵌类::函数名(形参表) {...}
/** 代码演示 **/#include <iostream>using namespace std;class List { //双向链表public:    List(): m_head(NULL), m_tail(NULL) { } private:    class Node { //双向链表节点 (内嵌类)    public:        Node(int d); //类内声明,类外实现        //类内声明,类内实现        Node(int d): m_data(d), m_next(NULL), m_prev(NULL) { }         int m_data;        Node *m_next;        Node *m_prev;    };  public:    void push_back(int v) {        if(NULL == m_tail) {            m_head = m_tail = new Node(v);//连续赋值        } else {            //其他实现代码        }       }   private:    Node *m_head;    Node *m_tail;};List::Node::Node(int d): m_data(d), m_next(NULL), m_prev(NULL) { } int main() {    List l1; //l1 链表封装    l1.push_back(100);//  List::Node n1(200); //私有的就不合法//  List::Node *node = new List::Node(300);    return 0;}

二、静态成员变量与函数 static  //全局的,作用域在类内
1. 静态成员变量/对象
1)静态成员变量的声明
class A {
static 对象类型 对象名(变量名);
};
2)静态成员变量的定义
对象类型 类名(A)::对象名 = 初值;

对象类型 类名(A)::对象名;
3)访问权限:公有,保护,私有
4)使用方法:
<1>在类内:直接用变量名访问
<2>在类外:
类名::静态成员变量名

对象名.静态成员变量名
/** 代码演示 **/#include <iostream>using namespace std;class BOC { //Bank of chinapublic:    BOC(): m_money(0) {}    void saveMoney(int m) { //存入非静态成员变量        m_money += m;    }       int getMnoey() { return m_money; }    void save(int m) {        s_money += m;    }       void showMoney() {        cout << "总钱数:" << s_money << endl;    }       int m_money;    static int s_money; //静态成员变量的声明};int BOC::s_money = 0; //定义+初始化int main(void) {    cout << BOC::s_money << endl; //1. 用类来访问    BOC t1;     t1.save(1000); //存入静态成员变量中    cout << t1.s_money << endl; //2. 用对象来访问    t1.showMoney(); //3. 用成员函数来访问    return 0;}

补充:
//C语言的静态全局变量可见范围为当前.c文件内
static int s_money = 0;
//C语言的静态函数的可见范围为当前.c文件内有效,C++也一样
static int * get_money_ptr() {
    return &s_money;
}

2. 静态成员函数
1)静态成员函数的声明:
class 类名 {
static 返回类型 函数名(形参表); //类内声明
static 返回类型 函数名(形参表) {...} //类内声明,类内实现
};
返回类型 类名::函数名(形参表) {...} //类外实现
2)说明
<1>静态成员函数/对象不属于某个对象,它属于某个类公有;
<2>静态成员函数内部没有 this 指针,它不能访问对象的成员变量;
<3>静态成员函数不能为常成员函数,即不能用 const 修饰;
/** 代码演示 **/#include <iostream>using namespace std;class A { public:    A() { s_global++; } //构造函数,根据静态变量的值知道对象个数    ~A() { s_global--; }    static int getCount() { //【静态成员函数】类内声明+实现        return s_global;    }       static void reset(); // 【静态成员函数】类内声明+类外实现    int m_a1; //4个字节private:    static int s_global; //静态成员变量不占对象的空间};void A::reset() { s_global = 0 }; //类外实现int A::s_global = 0; //全局void test() {    cout << A::getCount() << endl;}int main(void) {    cout << A::getCount() << endl;//0    test();//0    A a;    cout << sizeof(a) << endl; //4     cout << a.getCount() << endl;//1    A *p = new A;    cout << a.getCount() << endl;//2    test();//2    delete p;    p = NULL;    test();//1    A::reset();    cout << a.getCount() << endl;//0//  cout << a.s_global << endl; //0 (公有权限)//  cout << A::s_global << endl; //0 (公有权限)    return 0;}

三、单例模式  (静态成员函数的应用  - 23 中模式之一)
1)说明:
在整个应用程序内部,"在同一时刻,只允许有一个对象存在"的模式。
单例模式包含:
1. 禁止在类外部创建对象实例(私有构造函数 private)
2. 类自己维护其唯一实例(静态成员变量 static instance)
3. 提供访问该实例的方法(静态成员函数 static getInstance)
2)单例模式的实现方法:
<1>【饿汉式】:
将唯一的对象实现为静态成员对象,无论用与不用,程序启动就创建。
"优点":加载进程时创建单例对象,线程安全。
"缺点":无论是否使用,此对象一直存在,成员较大时占内存资源。
/** 代码演示 **/#include <iostream>using namespace std;class Singleton {public:    static Singleton & getInstance() {        return s_instance;    }       void doSomething() {        cout << "单例对象正在做事...\n";    }   private:    Singleton() {} //私有的构造函数//  Singleton *a; //这样定义在成员的上面合法,如链表:Node *next;    int bmp[1920*1080]; //很大    int s_member; //单例里的随意成员    static Singleton s_instance; //实例(先有占内存的成员变量)};Singleton Singleton::s_instance; //静态成员变量需要在类的外部实例化int main() {    //getInstance()为单例模式的接口,使用接口需要用引用接收    Singleton & a1 = Singleton::getInstance();    a1.doSomething();    Singleton & a2 = Singleton::getInstance();    a2.doSomething();    //类的对象始终只有一个    return 0;}

<2>【懒汉式】:
在需要的时候才动态创建这个对象,否则先不创建这个对象。
"优点":需要使用时,才创建单例对象,使用时才占内存资源。
"缺点":首次访问单例对象时,需要考虑线程安全("线程锁解决")。


/** 代码演示 - 考虑线程安全的【懒汉式】单例模式 **/#include <iostream>#include <pthread.h>using namespace std;class Singleton {public:    static Singleton * getInstance() {        pthread_mutex_lock(&s_lock); //线程上锁        if(NULL == s_pInstance) {            s_pInstance = new Singleton;        } //指针指向内容不为空才返回        pthread_mutex_unlock(&s_lock); //线程解锁        return s_pInstance;    }       void doSomething() {        cout << "单例对象正在做事...\n";    }   private:    Singleton() {} //私有的构造函数    int s_member; //单例里的随意成员    static Singleton *s_pInstance; //实例(先有占内存的成员变量)    static pthread_mutex_t s_lock; //声明线程锁};Singleton *Singleton::s_pInstance = NULL; //指针必须初始化//初始化线程锁pthread_mutex_t Singleton::s_lock = PTHREAD_MUTEX_INITIALIZER;void *thread_func(void *data) {    Singleton *p3 = Singleton::getInstance();    p3->doSomething();    return NULL;}int main() {    //getInstance()为单例模式接口,同时也是只有1个单例对象    Singleton *p1 = Singleton::getInstance();    p1->doSomething();    cout << "p1 address: " << p1 << endl; //0x9131008    Singleton *p2 = Singleton::getInstance();    p2->doSomething();    cout << "p2 address: " << p2 << endl; //0x9131008    return 0;}

四、成员指针 (仅作了解,可以不用)
1. 成员变量指针
1)语法定义:
类型 类名::*成员指针名;

类型 类名::*成员指针名 = &类名::成员对象名;
2)用法:(解引用)
对象.*成员指针
对象指针->*成员指针
int i = 10;
int *pi = &i;
*pi = 10; //*号也叫解引用运算符
/** 代码演示 **/#include <iostream>using namespace std;class A { public:    A(): a1(1), a2(2) { }     int a1;     int a2; };int main() {    int A::*pa = &A::a1; //成员指针 pa; 必须借助于某个对象    cout << "pa = " << pa << endl;    A a; //创建a对象    cout << "a.a1 = " << a.a1 << endl;    cout << "a.*pa = " << a.*pa << endl;    A *p = &a;     cout << "p->a1 = " << p->a1 << endl;    cout << "p->*pa = " << p->*pa << endl;    pa = &A::a2;    cout << "p->*pa = " << p->*pa << endl;    cout << "pa = " << pa << endl;    return 0;}

2. 成员函数指针
1)定义语法:
返回类型 (类名::*成员函数指针)(形参表);  //定义
或  //定义并初始化
返回类型 (类名::*成员函数指针)(形参表) = &类名::非静态成员函数名;
2)用法:
(对象.*成员函数指针名)(实参);
(对象指针->*成员函数指针名)(实参);
/** 代码演示 **/#include <iostream>using namespace std;class A { public:    A(): a1(1), a2(2) { }     void setA1A2(int i1, int i2) {        cout << "setA1A2\n";    }       void setA2A1(int i2, int i1) {        cout << "setA1A2\n";    }       int a1;     int a2; };int main() {    int A::*pa = &A::a1; //成员指针 pa; 必须借助于某个对象    cout << "pa = " << pa << endl;    A a; //创建a对象    cout << "a.a1 = " << a.a1 << endl;    cout << "a.*pa = " << a.*pa << endl;    A *p = &a;     cout << "p->a1 = " << p->a1 << endl;    cout << "p->*pa = " << p->*pa << endl;    pa = &A::a2;    cout << "p->*pa = " << p->*pa << endl;    cout << "pa = " << pa << endl;    //以下示意成员函数指针//  void (A::*pf)(int, int);    void (A::*pf)(int, int) = &A::setA1A2;    (a.*pf)(100, 200); //==> a.setA1A2(100, 200);    pf = &A::setA2A1;    (p->*pf)(1000, 2000); //==> p->setA2A1(1000, 2000);    return 0;}

五、友元函数
关键字 friend 全局函数返回值类型声明;
1. 友元函数的声明方法:
类内:friend 全局函数声明;
2. 说明
1)友元函数非成员函数,并且不受访问权限限定符限制;
2)友元函数只能是全局函数(不能是类内成员函数);

六、友元类
关键字 friend class 类名;
class A { };
class B {
friend class A;
};
1. 友元类A可以访问B类内所有类型的成员,不受访问限定符限制;
2. 说明:
1)友元类不能反向递推,A类为B类的友元,但B类不是A类的友元。
【总的说明】 友元实际破坏了类的封装性,最好少用或不用友元。
/** 友元函数、友元类的代码演示 **/#include <iostream>using namespace std;class Son { //compareMoney是Son的朋友friend bool compareMoney(Son &, Son &); //友元函数,公私都可访问friend class Father; //友元类,不受访问权限限定public:    Son(): m_money(0) {}    void getMoney(int m) {        m_money += m;    }       void showMoney() {        cout << "我的压岁钱是" << m_money << endl;    }   private:    int m_money; //儿子的钱包};bool compareMoney(Son & s1, Son & s2) {    return s1.m_money > s2.m_money;}class Father {public:    Father(): m_money(0) {}    void makeMoney(int m) { m_money += m; }    void makeMoney(Son & s) { //友元类让类实现单向访问 Father->Son        m_money += s.m_money;        s.m_money = 0;    }       void showMoney() {        cout << "父亲的钱是" << m_money << endl;    }   private:    int m_money;//父亲的钱包};int main(void) {    Son xiaowei;    Son xiaoyang;    xiaowei.getMoney(100);    xiaoyang.getMoney(200);    if(compareMoney(xiaoyang, xiaowei)) {        cout << "小杨钱多\n";    } else {        cout << "小魏钱多\n";    }    Father laowei;    laowei.makeMoney(800);    laowei.makeMoney(xiaowei);    laowei.showMoney();    return 0;}


0 0