c++ - 父类的后代即使在声明为朋友后也无法访问其宿主类的私有成员数据字段
问题描述
我正在为堆栈创建状态行为模式(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。
解决方案
推荐阅读
- mongodb - 从MongoDB中的数组中查找特定记录
- html - Angular *ngFor 不会在添加/删除时更新列表
- sql - trim、replace、left trim的函数解释SQL顺序
- docker - Kubernetes Pod 重启问题异常
- mysql - mysql中的行值应该是一一对应的
- servlets - 如何处理 URL 中带有 # 字符的 HTTP 请求
- cytoscape.js - 如何在 Cytoscape.JS 中淡化边缘?
- google-bigquery - 需要将字符串从一列分隔为多列,以';'分隔 bigquery中的分隔符
- python - Keras 训练一维数据向量
- javascript - 在javascript中触发点击事件有效,但实际的asp.net事件不会被触发