微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

父类的后代即使已声明为好友,也无法访问其宿主类的私有成员数据字段

如何解决父类的后代即使已声明为好友,也无法访问其宿主类的私有成员数据字段

我正在为堆栈创建状态行为模式(下图为Uml图)。我把StackState类作为一个朋友来使其后代访问Stack的私有数据字段。在这种情况下,即使在我将堆栈状态声明为我的朋友之后,EmptyState(属于StackState的子类)也无法访问Stack内部的私有数据字段。对于Visual Studio编译器,似乎抛出了编译时错误C2248,我不知道是什么原因引起的。除了将Stack的数据字段公开之外,我已经尝试了所有方法,因为它违反了将堆栈状态设置为好友类的目的(为此,我希望其后代能够访问Stack的私有数据字段)。我还必须省略Stackstate的其他子类,以生成最少的代码来产生错误。因此,当我推入堆栈并尝试更改状态时,此代码仅包含空状态。因此,从本质上讲,我希望emptyState访问Stack的私有数据字段。

在stack.hpp

#include <iostream>
#include <algorithm>
#include <vector>
#include <memory>
#ifndef  STACKHPP
#define  STACKHPP
template<typename T>
class StackState;

template<typename T>
class Stack
{
private:
    std::vector<T>data;
    int top_index;
    std::shared_ptr<StackState<T>>state;
    void Init(int size);
private:
    
    friend class StackState<T>;
    void changeState(const std::shared_ptr<StackState<T>> source);
    //int get_top_index() const ;
    //std::vector<T>& get_data() const;
public:
    
    Stack();                    //Defualt constructor
    Stack(int size);
    Stack(const Stack <T>& source); //copy constructor
    Stack(Stack <T>&& target);      //Move constructors
    Stack <T>& operator=(const Stack <T>& source);
    Stack <T>& operator=(Stack&& target);   //Move semantics
    
    void Push(const T& data);
    T& Pop();
};
#ifndef STACKCPP
#include "Stack.cpp"
#endif // !STACKCPP
#endif

在Stack.cpp中

#include "Stack.hpp"
#include "StackState.hpp"
#include "EmptyState.hpp"
#ifndef  STACKCPP
#define  STACKCPP
template<typename T>
Stack<T>::Stack()
{
    Init(1);
}
template<typename T>
Stack<T>::Stack(int size)
{
    Init(size);
}
template<typename T>
Stack<T>::Stack(const Stack<T>& source) : data(source.data),top_index(source.top_index),state(source.state)
{
}
template<typename T>
Stack<T>::Stack(Stack<T>&& target) : data(std::move(target.data)),top_index(std::move(target.top_index)),state(std::move(target.state))
{
}
template<typename T>
Stack<T>& Stack<T>::operator=(const Stack<T>& source)
{
    if (this == &source)
    {
        return *this;
    }
    data = source.data;
    top_index = source.top_index;
    state = source.state;
    return *this;
    // Todo: insert return statement here
}
template<typename T>
Stack<T>& Stack<T>::operator=(Stack&& target)
{
    if (this == &target)
    {
        return *this;
    }
    data = std::move(target.data);
    top_index = std::move(target.top_index);
    state = std::move(target.state);
    return *this;
}
template<typename T>
void Stack<T>::changeState(const std::shared_ptr<StackState<T>> source)
{
    state = source;
}
template<typename T>
void Stack<T>::Init(int size)
{
    if (size < 1)
        data = std::vector<T>(1);
    else
        data = std::vector<T>(size);
    top_index = 0;
    
    state = std::make_shared<EmptyState<T>>();
}
template<typename T>
void Stack<T>::Push(const T& data)
{
    state->Push(*this,data);
}
template<typename T>
T& Stack<T>::Pop()
{
    return state->Pop(*this);
}
#endif // ! StackCPP

在StackState.hpp中

#include "Stack.hpp"
#ifndef  STACKSTATE_HPP
#define  STACKSTATE_HPP
template<typename T>
class Stack;
template<typename T>
class StackState
{

public:
    virtual T& Pop(Stack<T>& data);
    virtual void Push(Stack<T>& dat,const T& data);
};
#ifndef STACKSTATE_CPP
#include "StackState.cpp"
#endif // !STACKSTATE_CPP
#endif // ! STACKSTATE_HPP

以及在StackState.cpp中

#include "StackState.hpp"

#ifndef  STACKSTATE_CPP
#define  STACKSTATE_CPP
template<typename T>
T& StackState<T>::Pop(Stack<T>& data)
{
    data.top_index--;
    return data.data[data.top_index];
}

template<typename T>
void StackState<T>::Push(Stack<T>& data,const T& data_m)
{
    data.data.push_back(data_m);
    data.top_index++;
}

#endif // ! STACKSTATE_CPP

最后是EmptyStack.hpp和EmptyStack.cpp。主文件已包含在内

//#include "NotFullEmptyState.hpp"
//#include "FullState.hpp"
#include "StackState.hpp"
#ifndef EMPTYSTATE_HPP
#define EMPTYSTATE_HPP
template<typename T>
class EmptyState :public StackState<T>
{
public:
    virtual T& Pop(Stack<T>& data) override;
    virtual void Push(Stack<T>& dat,const T& data) override;
};

#ifndef EMPTYSTATE_CPP
#include "EmptyState.cpp"
#endif // !STACKSTATE_CPP
#endif // ! STACKSTATE_HPP
#include "EmptyState.hpp"
#ifndef EMPTYSTATE_CPP
#define EMPTYSTATE_CPP

template<typename T>
T& EmptyState<T>::Pop(Stack<T>& data)
{
    throw std::exception("You cannot pop an empty stack");
}

template<typename T>
void EmptyState<T>::Push(Stack<T>& dat,const T& data)
{

    StackState<T>::Push(dat,data);
//This is whats generating the error.The condition below.
    **if (dat.top_index == dat.data.size())
        dat.changeState(std::make_shared<EmptyState<T>>());**
    else
        dat.changeState(std::make_shared<EmptyState<T>>());
}

#endif // !1

最后是主要

#include "Stack.hpp"
int main()
{
    try
    {
        //Reserve 5 elements on the stack 
        Stack<int>data(5);
        data.Push(15);
        data.Push(14);
        data.Push(11);
        data.Push(16);
        data.Push(25);
        std::cout << data.Pop() << std::endl;
        std::cout << data.Pop() << std::endl;
        std::cout << data.Pop() << std::endl;
        std::cout << data.Pop() << std::endl;
        std::cout << data.Pop() << std::endl;
    }
    catch (const std::exception& error)
    {
        std::cout << error.what() << std::endl;
    }
}

最后,对于那些对设计模式感兴趣的人,这里是其后的状态UML过渡图。我没有包含fullstate和notFullEmptyState来生成最小数量代码

The state transition diagram

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。