c++ - 如何从其他结构访问 protected 结构变量

标签 c++ vector struct protected

所以我正在编写一个 C++ 程序来模拟图书证目录。我为卡片和每张卡片上的所有信息定义了一个 struct,以及一个工作 vectoriterator 来访问/打印所有变量使用全局无效函数指定的卡。

现在,我想在一个新定义的 struct 中移动那个 void 函数,Catalog 处理所有处理借书证的方法,比如 insert/ push_backsearchremove/erase/pop_back。我还希望 card 下的变量受到 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("%s\n", it->title.c_str());
            printf("%s\n", 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 下的 protected 变量以便打印 protected 变量?

不能像在目录中列出 friend struct Card 那样简单吗?

编辑:我试了一下,发现 Card 下的 friend struct Catalog 能够消除它尝试访问的 protected 变量的 void 函数中的错误。尽管我将 main 中的所有对象都定义为 Card,但我仍在努力让 main pass through catalog。

我想我可以尝试在 main 中调用 setCard(),在 Catalog 中定义,它使用 vector 来引用 protected 变量。

最佳答案

有多种方法可以做到,正确的方法取决于上下文。以下是一些可能的解决方案,从最简单/最难的到最冗长/最难的(不是详尽的 list ):


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("%s\n", it->title.c_str());
                    printf("%s\n", it->name.c_str());
                }
        }
}

虽然这确实解决了问题,但这不是一个好的解决方案。如果您想更改成员(member)的姓名 titlemain_title你这样做会很痛苦,因为你必须编辑每一次出现的title。这很快就会变得一团糟。


2。制作void showCard(vector<Card> test)一个friend结构 Card

如果void showCard(vector<Card> test)Card的 friend 然后它将可以访问 Card 的所有 protected 和私有(private)成员好像他们是公开的。这是一个很好的解决方案,因为只有 void showCard(vector<Card> test)将有权访问这些 protected 成员。

因为您只能成为先前声明函数的友元,所以您需要转发声明函数 void showCard(vector<Card> test)在声明Card之前.

但是,因为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("%s\n", it->title.c_str());
                    printf("%s\n", it->name.c_str());
                }
        }
}

3。创建get三和set Card 条款

This is one of the canonical implementations .每次将成员设为私有(private)/ protected 时,您都会提供 get_member和一个 set_member方法。

这样每个人都可以访问该成员,但是,他们只有在使用这些方法时才能访问它。您甚至可以为不存在的成员创建 getter/setter(即您在需要时计算它们)。

既然代码胜于 Eloquent ,下面是一个实现:

...

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("%s\n", it->get_title().c_str());
                    printf("%s\n", it->get_name().c_str());
                }
        }
}

如果您想更改成员(member)的姓名 titlemain_title , 你只需要编辑 get_titleset_title并且您的所有代码将继续工作,就好像您根本没有更改它一样。您甚至可以删除该成员或执行任何其他操作(例如从数据库中获取它),因为它存在且名称重要的唯一位置是在 get_title 中。和 set_title .如果没有 getter 和 setter,您将需要编辑每一次出现的 title。为了做到这一点。

getter 和 setter 也是改进 const correctness 的好地方您的代码,使其更加健壮和高效。 const 正确的 get/set 对看起来像这样:

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 来修改解决方案 3并放置 void showCard(vector<Card> test)在里面。这不是一个通常的解决方案,它打开了我们摆脱一些全局变量(全局变量几乎总是邪恶的)并隐藏我们正在使用 vector<Card> 的事实的可能性。保持Card s(我们可以使用 hashmap 而不是 vector,这样也可以,这样其他代码就不需要知道我们从两者中选择了哪一个)。

//#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("%s\n", it->getTitle().c_str());
                        printf("%s\n", 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;
}

完成程序编写后,您可能有兴趣在 Code Review 上展示它以获得关于其他人如何处理相同代码的见解,并了解更有经验或具有不同背景的人如何编写此类代码。

关于c++ - 如何从其他结构访问 protected 结构变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52546965/

相关文章:

c++ - 使用 C++ 在微 Controller 上显示位图图形

c++ - 我的自动指针即使在所有权转移后也能正常工作

c++ - 将字符串拆分为 vector C++

c++ - 具有基于位置的枚举编译错误的结构

c++ - atof 随机无法正常工作

c++ - 访问 vector 的元素

c++ - STL vector 、迭代器和插入 (C++)

c - 如何将结构成员用于算术运算符(add、sub、mul、div 变量到结构成员)

c - 这个位域会按我预期的方式工作吗?

c++ - 在 OpenCV 中,设置曝光会导致我的网络摄像头软件无法自动调整曝光