【C++笔记】十四、友元类和嵌套类

1.友元类

#include <iostream>
using namespace std;

class TV  // 电视机
{
private:
    bool mState = false; // true:开  false:关
    int mProgramIndex = 0;  //  节目索引
public:
    friend class RemoteController; // 友元类,友元类可以访问当前类的私有内容
    bool getState();
    int getProgramIndex();
};

bool TV::getState()
{
    return mState;
}

int TV::getProgramIndex()
{
    return mProgramIndex;
}

class RemoteController  // 遥控器
{
public:
    void setState(TV &tv)
    {
        tv.mState = !tv.mState;
    }
    void setProgramIndex(TV &tv, int programIndex)
    {
        if(tv.mState)
        {
            tv.mProgramIndex = programIndex;
        }
        else
        {
            cerr << "电视机未打开,无法设置频道." << endl;
        }
    }    
};

int main(int argc, const char * argv[]) {
    // 友元类
    TV tv;
    RemoteController remoteController;
    
    remoteController.setState(tv);
    remoteController.setProgramIndex(tv, 12);
    
    cout << "开关机状态:" << ((tv.getState())?"开机":"关机") << endl; // 开机
    cout << "频道:" << tv.getProgramIndex() << endl;             // 12
   
    return 0;
}

2.友元成员方法

将某一个类的某些方法单独设为另外一个类的友元方法

#include <iostream>
using namespace std;

/*
在一个类中使用另外一个类的两种情况:
 1.  只是引用  void setState(TV &tv)   TV只需要在前面声明即可
 2.  访问了类型中的成员   类型必须在前面定义(具体实现里面的内容)
*/

//第3步 声明TV以配合RemoteController
class TV;
//第2步 RemoteController需要在TV前面声明,否则编译器会因为找不到RemoteController报错
class RemoteController
{
public:
    void setState(TV &tv); // 这里的TV要求Class TV在前面,二者矛盾
// 如果方法在类的内部实现的话就涉及到了访问类中成员,那就不是一个class TV;能解决的了
// 所以方法的声明写在这里,方法的定义要写在Class TV的后面,才不会报错,方法的定义就要使用inline关键字了
    void setProgramIndex(TV &tv, int programIndex); 
    void process(TV &tv);
};

class TV
{
private:
    bool mState = false; // true:开  false:关
    int mProgramIndex = 0;  //  节目索引
public:
    //  第1步 声明友元成员方法
    friend void RemoteController::setState(TV &tv); // 这里要求RemoteController在前面
    friend void RemoteController::setProgramIndex(TV &tv, int programIndex);
    
    bool getState();
    int getProgramIndex();
};
bool TV::getState()
{
    return mState;
}
int TV::getProgramIndex()
{
    return mProgramIndex;
}

//第4步,RemoteController的方法实现中因为涉及到了访问类型中成员,所以
//
inline void RemoteController::setState(TV &tv)
{
    tv.mState = !tv.mState;
}
inline void RemoteController::setProgramIndex(TV &tv, int programIndex)
{
    if(tv.mState)
    {
        tv.mProgramIndex = programIndex;
    }
    else
    {
        cerr << "电视机未打开,无法设置频道." << endl;
    }
    //tv.mState = 20;
}
void RemoteController::process(TV &tv) 
{
   // tv.mState = 20;  //报错,因为这个方法不是TV类的友元方法,无法访问TV类中的私有成员
}

int main(int argc, const char * argv[]) {
    // 友元成员方法
    // remoteController中的两个方法是TV中的友元方法,这两个方法可以调用TV中的私有内容
    TV tv;
    RemoteController remoteController;
    
    remoteController.setState(tv);
    remoteController.setProgramIndex(tv, 12);
    
    cout << "开关机状态:" << ((tv.getState())?"开机":"关机") << endl;
    cout << "频道:" << tv.getProgramIndex() << endl;
 
    return 0;
}

3.互为友元类

#include <iostream>
using namespace std;

class RemoteController;

class TV
{
private:
    bool mState = false; // true:开  false:关
    int mProgramIndex = 0;  //  节目索引
public:
    friend class RemoteController;
    bool getState();
    int getProgramIndex();
    void reply(RemoteController &rc);
};

bool TV::getState()
{
    return mState;
}

int TV::getProgramIndex()
{
    return mProgramIndex;
}

class RemoteController
{
private:
    string mAudioStr;
public:
    friend class TV;
    void setState(TV &tv)
    {
        tv.mState = !tv.mState;
    }
    void setProgramIndex(TV &tv, int programIndex)
    {
        if(tv.mState)
        {
            tv.mProgramIndex = programIndex;
        }
        else
        {
            cerr << "电视机未打开,无法设置频道." << endl;
        }
    }    
};

void TV::reply(RemoteController &rc)
{
    rc.mAudioStr = "非常抱歉,没有搜索到您指定的频道.";
    cout << rc.mAudioStr << endl;
}

int main(int argc, const char * argv[]) {
    // 互为友元类
    TV tv;
    RemoteController remoteController;
    
    remoteController.setState(tv);
    remoteController.setProgramIndex(tv, 12);
    
    cout << "开关机状态:" << ((tv.getState())?"开机":"关机") << endl;
    cout << "频道:" << tv.getProgramIndex() << endl;
    
    tv.reply(remoteController);
    
    return 0;
}

4.共同的友元函数

#include <iostream>
using namespace std;

class MyClass2;

class MyClass1
{
private:
    string mName;
    friend void process(MyClass1 &c1, MyClass2 &c2); // 只是引用了MyClass2,所以在在前面声明就好
};

class MyClass2
{
private:
    int mCode;
    friend void process(MyClass1 &c1, MyClass2 &c2);
};

void process(MyClass1 &c1, MyClass2 &c2)
{
    c1.mName = "Bill Gates";
    c2.mCode = 200;
    cout << "c1.mName = " << c1.mName << " c2.mCode = " << c2.mCode << endl;
}

int main(int argc, const char * argv[]) {
    // 共同的友元函数
    MyClass1 c1;
    MyClass2 c2;
    process(c1, c2); // Bill Gates  200
    return 0;
}

5.嵌套类基础

#include <iostream>
using namespace std;

class MyClass
{
public:
    class InnerClass
    {
    private:
        int mCode = 100;
    public:
        int getCode();
        void setCode(int code)
        {
            mCode = code;
        }
    };
    InnerClass* getInnerClass() // 将内嵌类作为返回值
    {
        return new InnerClass();
    }
};

int MyClass::InnerClass::getCode()  // 内嵌类的方法在外部的定义/实现
{
    return mCode;
}

int main(int argc, const char * argv[]) {
    // 内嵌类
    MyClass::InnerClass innerClass; // 内嵌类的生成
    innerClass.setCode(200);  
    cout << innerClass.getCode() << endl;  // 200
    MyClass myClass;
    cout << myClass.getInnerClass()->getCode() << endl; // 100
    
    return 0;
}

6.嵌套类的访问权限

        private:只有宿主类知道嵌套类的存在,嵌套类对于外部(包括宿主类的外部和宿主类的派生类)是隐藏的
        protected:只有宿主类知道嵌套类的存在,嵌套类对于外部(包括宿主类的外部和宿主类的派生类)是隐藏的
        public:访问权限没有限制

#include <iostream>
using namespace std;

class MyClass
{
private:   // 不能被子类继承
    class InnerClass1
    {
    public:
        int code = 50;
    };
protected:  // 可以被子类继承,但只能是引用形式
    class InnerClass2
    {
    public:
        int code = 100;
    };
public:
    class InnerClass3
    {
    public:
        int code = 200;
    };
    
    InnerClass1* getInnerClass1()
    {
        return new InnerClass1();
    }    
};

class SubClass : public MyClass
{
public:
    InnerClass2* getInnerClass2()
    {
        return new InnerClass2();
    }
    
    InnerClass3* getInnerClass3()
    {
        return new InnerClass3();
    }
};

int main(int argc, const char * argv[]) {
	
    MyClass myClass;
   /* MyClass::InnerClass1 *innerClass1 = myClass.getInnerClass1(); 
   会报错,myClass.getInnerClass1()的返回值不能赋值给变量,像下句那样直接
   对返回的内容操作是可以的*/
    cout << myClass.getInnerClass1()->code << endl;  // 50
    
    SubClass subClass;
    cout << subClass.getInnerClass2()->code << endl;  // 100

    SubClass::InnerClass3 *innerClass3 = subClass.getInnerClass3();
    cout << innerClass3->code << endl;      // 200
    return 0;
    
}

7.模板类中的嵌套类

#include <iostream>
using namespace std;

template <class T>
class Queue
{
private:
    class Item
    {
    public:
        T value;
        Item* next;
    // 构造方法,同时初始化value为传入参数v,初始化指针next为nullptr
        Item(const T& v):value(v),next(nullptr) 
        {
            
        }
    };
    Item* mFirstItem;   //  队列的第一个元素的指针,指向一个类
    Item* mLastItem;    //  队列的最后一个元素的指针,指向一个类
public:
    void enqueue(const T &value);   //  入队,函数声明
    bool dequeue(T &value);         //  出队,函数声明
    T* getQueueTop()
    {
        if(mFirstItem != nullptr)
        {
            return &mFirstItem->value; //理解为&(mFirstItem->value),返回的是值的地址,不是值本身
        }
        else
        {
            return nullptr;
        }
    }
    
    Queue():mFirstItem(nullptr), mLastItem(nullptr)
    {
        
    }
};

template <class T>
void Queue<T>::enqueue(const T& value) // 模板类的方法
{
    Item *item = new Item(value);
    if(mFirstItem == nullptr)
    {
        mFirstItem = item;
        mLastItem = item;
    }
    else
    {
        mLastItem->next = item;
        mLastItem = item;  // 将新入队的值,插到队列尾部
    }    
}

template <class T>
bool Queue<T>::dequeue(T &value)  // 出队,是出队列头部,方法将出队的值赋给传入的value
{
    if(mFirstItem == nullptr)
    {
        return false;
    }
    value = mFirstItem->value;
    Item *tempItem = mFirstItem;
    mFirstItem = mFirstItem->next;
    delete tempItem; // 删除出队节点
    return true;
}

int main(int argc, const char * argv[]) {
    // 模板类中的嵌套类
    Queue<string> strQueue;
    strQueue.enqueue("xyz");
    strQueue.enqueue("龙腾虎跃");
    cout << *strQueue.getQueueTop() << endl; // xyz
    
    string value;
    strQueue.dequeue(value);
    cout << *strQueue.getQueueTop() << endl; // 龙腾虎跃
    cout << value << endl;								// xyz
    
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DUANDAUNNN

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值