有多种方法可以做到这一点,正确的方法取决于上下文。以下是一些可能的解决方案,从最简单/最骇人听闻的到最冗长/最难的(不是详尽的列表):
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());
}
}
}
虽然这确实解决了问题,但它不是一个好的解决方案。如果您想将成员 title 的名称更改为 main_title,这样做会很痛苦,因为您必须编辑每一个出现的 title,这会很快变得混乱。
2。使void showCard(vector<Card> test) 成为结构Card 的friend
如果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("%s\n", it->title.c_str());
printf("%s\n", it->name.c_str());
}
}
}
3。为Card 创建getters 和setters
This is one of the canonical implementations。每次将成员设为私有/受保护时,您都会为其提供 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("%s\n", it->get_title().c_str());
printf("%s\n", it->get_name().c_str());
}
}
}
如果您想将成员 title 的名称更改为 main_title,您只需编辑 get_title 和 set_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 并将 void showCard(vector<Card> test) 放入其中来修改解决方案 3。这不是一个常见的解决方案,让我们有可能摆脱一些全局变量(全局变量几乎总是邪恶的)并隐藏我们使用vector<Card> 来保留Cards 的事实(我们可以使用哈希图而不是向量,这也可以,因此其他代码不需要知道我们在两者中选择了哪一个。
//#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 上展示它,以便了解其他人如何处理相同的代码,并了解更有经验或具有不同背景的人如何编写此类代码.