如何从其他结构访问受保护的结构变量
How to access protected structure variables from other structures
所以我正在编写一个C++程序,它将模拟一个库卡目录。我为卡和每张卡上的所有信息定义了一个struct
,以及一个工作的vector
和iterator
,以使用全局void函数访问/打印指定卡上的全部变量。
现在,我想在新定义的struct
目录中移动void函数,该目录处理所有处理库卡的方法,如insert
/push_back
、search
或remove
/erase
/pop_back
。我还希望卡片下的变量是protected
,因为我经常被告知将类/结构变量设置为private
是一种很好的编码实践(我为继承的其他类设置了protected
)。
//#include <cstdio>
#include <iostream>
//#include <stdio.h>
#include <vector>
#include <string>
using namespace std;
struct Card
{
public:
Card(string title, string name)
{
this->title = title;
this->name = name;
}
//protected:
string title = "Unknown";
string name = "Unknown";
};
vector<Card> test;
vector<Card>::iterator it;
void showCard(vector<Card> test)
{
for (it = test.begin(); it != test.end(); it++)
{
if (it->title != "Unknown")
{
printf("%sn", it->title.c_str());
printf("%sn", it->name.c_str());
}
}
}
int main()
{
Card book1 = { "Serpent in the heather / Kay Kenyon", "Kay Kenyon"};
Card book2 = { "USA and the Middle East since World War 2 /
T.G. Fraser.", "T.G. Fraser"};
Card book3 = { "My Horse and wally", "Jason Weber" };
test.push_back(book1);
test.push_back(book2);
test.push_back(book3);
showCard(test);
getchar();
return 0;
}
我想我的问题是,我如何从main调用Catalog结构,然后访问Card下的受保护变量,以便打印受保护的变量?
不能像在目录中列出friend struct Card
那样简单吗?
编辑:我仔细研究了一下,发现Card下的friend struct Catalog
能够消除它试图访问的受保护变量的void函数中的错误。尽管main
中的所有对象都定义为Card
,但我仍在努力使主传递目录通过。
我想我可以尝试一个在main中调用的setCard()
,它在Catalog中定义,使用向量引用受保护的变量。
有多种方法,正确的方法取决于上下文。以下是一些可能的解决方案,从最简单/最黑客的到最冗长/最难的(不是详尽的列表):
1.只要公开一切
...
struct Card{
public:
Card(string title, string name){
this->title = title;
this->name = name;
}
string title = "Unknown";
string name = "Unknown";
};
...
void showCard(vector<Card> test){
for (it = test.begin(); it != test.end(); it++){
if (it->title != "Unknown"){
printf("%sn", it->title.c_str());
printf("%sn", it->name.c_str());
}
}
}
虽然这确实解决了问题,但不是一个好的解决方案。如果你想将成员title
的名称更改为main_title
,你会很痛苦,因为你必须编辑title
的每一次出现,这可能会很快变得混乱。
2.让void showCard(vector<Card> test)
成为结构体Card
的朋友
如果void showCard(vector<Card> test)
是Card
的朋友,那么它将可以访问Card
的所有受保护和私有成员,就好像它们是公共的一样。这是一个不错的解决方案,因为只有void showCard(vector<Card> test)
才能访问这些受保护的成员。
因为您只能是以前声明的函数的朋友,所以需要在声明Card
之前转发声明函数void showCard(vector<Card> test)
。
但是,由于void showCard(vector<Card> test)
采用vector<Card>
参数,因此类Card
需要在函数的正向声明之前进行正向声明。
...
struct Card;
void showCard(vector<Card> test);
struct Card{
public:
friend void showCard(vector<Card> test);
Card(string title, string name){
this->title = title;
this->name = name;
}
protected:
string title = "Unknown";
string name = "Unknown";
};
...
void showCard(vector<Card> test){
for (it = test.begin(); it != test.end(); it++){
if (it->title != "Unknown"){
printf("%sn", it->title.c_str());
printf("%sn", it->name.c_str());
}
}
}
3.为Card
创建get
ter和set
ter
这是规范的实现之一。每次您将成员设为私有/受保护时,都会为其提供get_member
和set_member
方法。
这样,每个人都可以访问该成员,但是,他们只有在使用这些方法时才能访问该成员。您甚至可以为不存在的成员创建getter/setter(即,在需要时计算它们)。
由于代码不仅仅是文字,这里有一个实现:
...
struct Card{
protected:
string title = "Unknown";
string name = "Unknown";
public:
Card(string title, string name){
this->title = title;
this->name = name;
}
string get_title(){
return this->title;
}
void set_title(string new_title){
this->title = new_title;
}
string get_name(){
return this->name;
}
void set_name(string new_name){
this->name = new_name;
}
};
...
void showCard(vector<Card> test){
for (it = test.begin(); it != test.end(); it++){
if (it->get_title() != "Unknown"){
printf("%sn", it->get_title().c_str());
printf("%sn", it->get_name().c_str());
}
}
}
如果您想将成员title
的名称更改为main_title
,则只需编辑get_title
和set_title
,所有代码都将继续工作,就像您根本没有更改它一样。您甚至可以删除该成员或做任何其他事情(比如从数据库中获取它),因为它的存在和名称唯一重要的地方是在get_title
和set_title
中。如果没有getter和setter,您将需要编辑title
的每一次出现才能做到这一点。
Getter和setter也是提高代码常量正确性的好地方,使其更加健壮和高效。一个常量正确的获取/设置对看起来像这样:
const string& get_title() const {
return this->title;
}
void set_title(const string& new_title){
this->title = new_title;
}
一个不存在的成员的配对看起来是这样的:
#include <string>
#include <algorithm>
#include <iterator>
string get_title_and_name(){
// Concatenates the title and name
return this->title + " / " + this->name;
}
void set_title_and_name(string new_string){
// Splits the string between a title and a name
std::size_t split_point = 0;
split_point = new_string.find('/');
this->title = new_string.substr(0, split_point);
// We don't want to include the char '/' of
// the new_string in this->name, so use
// (split_point + 1) instead of split_point
this->name = new_string.substr(split_point + 1, new_string.size() - (split_point + 1));
}
虽然此解决方案可能比其他解决方案更详细,但它也更灵活。
建议的解决方案
我们可以通过创建一个新的结构Catalog
并将void showCard(vector<Card> test)
放入其中来修改解决方案3。这不是一个常见的解决方案,让我们有可能去掉一些全局变量(全局变量几乎总是邪恶的),并隐藏我们使用vector<Card>
来保持Card
s的事实(我们可以使用哈希图而不是向量,这也会起作用,这样其他代码就不需要知道我们在这两者中选择了哪一个)。
//#include <cstdio>
#include <iostream>
//#include <stdio.h>
#include <vector>
#include <string>
using namespace std;
// As in solution 3
struct Card {
protected:
string title = "Unknown";
string name = "Unknown";
public:
Card(string title, string name){
this->title = title;
this->name = name;
}
// Right now we only need getters,
// but we could have setters as well
// (the names are in camelCase to follow
// showCard() naming convention)
string getTitle(){
return this->title;
}
string getName(){
return this->name;
}
};
struct Catalog {
protected:
// This one was a global variable previously
// Also we don't specify a default value
// for it here, we will do that in the constructor
vector<Card> test;
public:
Catalog(){
// The start value of test will be a empty vector
this->test = vector<Card>();
}
// We moved void showCard(vector<Card> test) to here
void showCard(){
// This is a local variable now
vector<Card>::iterator it;
// For loop as in solution 3
for (it = this->test.begin(); it != this->test.end(); it++){
if (it->getTitle() != "Unknown"){
printf("%sn", it->getTitle().c_str());
printf("%sn", it->getName().c_str());
}
}
}
// A new method for adding cards,
// because external code shouldn't care
// about how we add or remove card or even
// if we store cards in this machine or in a web server
void addCard(Card card){
this->test.push_back(card);
}
};
int main()
{
Card book1 = { "Serpent in the heather / Kay Kenyon", "Kay Kenyon"};
Card book2 = { "USA and the Middle East since World War 2 / T.G. Fraser.", "T.G. Fraser"};
Card book3 = { "My Horse and wally", "Jason Weber" };
Catalog catalog;
catalog.addCard(book1);
catalog.addCard(book2);
catalog.addCard(book3);
// We could even do something like
// catalog.addCard({ "My Horse and wally", "Jason Weber" });
// thankfully to the new addCard method.
// We wouldn't even need to declare book1, book2 and book3
// if we used it that way
catalog.showCard();
getchar();
return 0;
}
在你写完你的程序后,你可能有兴趣在代码审查上展示它,以便了解其他人将如何处理相同的代码,并了解更有经验或有不同背景的人将如何编写此类代码。
@obidyne,欢迎使用StackOverflow。如果您的目标是保护成员,但仍然能够显示它们(作为格式化字符串),那么您可以实现一个公共方法showCard
,重命名另一个函数showCards
,并为向量的每个对象调用公共方法。
举个例子(使用您自己的代码):
//#include <cstdio>
#include <iostream>
//#include <stdio.h>
#include <vector>
#include <string>
using namespace std;
struct Card
{
public:
Card(string title, string name)
{
this->title = title;
this->name = name;
}
void showCard()
{
if (this->title != "Unknown")
{
printf("%sn", this->title.c_str());
printf("%sn", this->name.c_str());
}
}
protected:
string title = "Unknown";
string name = "Unknown";
};
vector<Card> test;
vector<Card>::iterator it;
void showCards(vector<Card> test)
{
for (it = test.begin(); it != test.end(); it++)
{
it->showCard();
}
}
int main()
{
Card book1 = { "Serpent in the heather / Kay Kenyon", "Kay Kenyon"};
Card book2 = { "USA and the Middle East since World War 2 /
T.G. Fraser.", "T.G. Fraser"};
Card book3 = { "My Horse and wally", "Jason Weber" };
test.push_back(book1);
test.push_back(book2);
test.push_back(book3);
showCards(test);
getchar();
return 0;
}
- C++:无法访问声明的受保护成员
- 继承和友元函数,从基类访问受保护的成员
- 为什么派生类的好友不能使用受保护的成员?
- C++:为什么无法在派生类中访问受保护的构造函数?
- 公共/私有/受保护是否会更改内存中结构的排列?
- 在父类中公开受保护的构造函数
- 如何从其他结构访问受保护的结构变量
- 如何实现返回受保护结构的私有函数
- 相同的层次结构,访问基类的受保护成员时的行为不同
- 从模板化父类中的派生内部类访问受保护的成员变量
- 为什么继承的受保护构造函数不能公开?
- 在使用受保护和继承时无法访问在类中声明的私有成员
- C++中的受保护变量
- 在此上下文中受保护 c++
- 同一模板类但模板类型的受保护成员
- 基类中受保护的纯虚函数如何被基类的友元类使用?
- 受保护的嵌套结构不能用作派生外部类中的返回类型?
- 从嵌套结构调用受保护的基类函数
- 将受保护的结构成员分配给朋友
- 在受保护的匿名联合的匿名结构中定义的成员仍然公开可见