get和set函数在C++;程序员? 我最初来自C的世界,我在学习C++。我一直在想C++中的get和SET函数。在C#中,这些工具的使用非常流行,而Visual Studio等工具通过使其易于快速实现来促进使用。然而,在C++世界中,情况似乎并非如此。
以下是C#2.0代码:get和set函数在C++;程序员? 我最初来自C的世界,我在学习C++。我一直在想C++中的get和SET函数。在C#中,这些工具的使用非常流行,而Visual Studio等工具通过使其易于快速实现来促进使用。然而,在C++世界中,情况似乎并非如此。,c#,c++,properties,C#,C++,Properties,以下是C#2.0代码: public class Foo { private string bar; public string Bar { get { return bar; } set { bar = value; } } } 或者,在C#3.0中: 也许人们会说,这有什么意义?为什么不创建一个公共字段,然后在需要时将其作为属性;老实说,我真的不确定。我只是出于良好的实践,因为我已经看过很多次了 因为我已经习惯了,我觉得我应
public class Foo
{
private string bar;
public string Bar
{
get { return bar; }
set { bar = value; }
}
}
或者,在C#3.0中:
也许人们会说,这有什么意义?为什么不创建一个公共字段,然后在需要时将其作为属性;老实说,我真的不确定。我只是出于良好的实践,因为我已经看过很多次了
因为我已经习惯了,我觉得我应该把这个习惯转交给我的C++代码,但是这真的是必要的吗?我没有看到像C#那样经常这样做
无论如何,这里的C++来自我收集的:class Foo
{
public:
std::string GetBar() const; // Thanks for the tip, @Daniel Earwicker.
void SetBar(std::string bar);
private:
std::string bar;
}
std::string Foo::GetBar() const
{
return bar;
}
void Foo::SetBar(std::string bar)
{
// Also, I always wonder if using 'this->' is good practice.
this->bar = bar;
}
现在,对我来说,这似乎是一个很大的腿部工作;考虑到使用VisualStudio的工具,C语言实现将花费字面的时间来实现,C++花费了我更长的时间来进行类型化,我觉得它不值得付出努力,特别是当替代的是5行长:
class Foo
{
public:
std::string Bar;
}
据我所知,这些是优点:
- 您可以更改get和set函数的实现细节,因此可以返回更有趣的内容,而不是返回私有字段
- 您可以稍后删除get/set,并将其设为只读/写(但对于面向公众的接口,这似乎不太好)
- 打字需要时间,这真的值得努力吗?一般来说。在某些情况下,这些优势使其值得付出努力,但我的意思是,就“良好实践”而言,是吗
GetBalance()
的函数呢
当然,这将比PrintBalance()更加通用;如果我想用另一种方式向用户展示它,而不是像类希望的那样,该怎么办?现在,在某种意义上,GetBalance()
可能不足以证明“getter和setter是好的”,因为它没有(或者可能不应该)一个附带的setter,而说到这个,一个名为SetBalance(float f)
的函数可能是坏的(在我看来)因为这会向函数的实现者暗示帐户必须在类的外部操作,这不是一件好事。在您的示例中:
class Foo
{
public:
const std::string GetBar(); // Should this be const, not sure?
你可能是说:
std::string GetBar() const;
将const
放在末尾意味着“此函数不修改它所调用的Foo实例”,因此在某种程度上它将其标记为纯getter
<>纯C++在C++中经常出现。std::ostringstream
中的一个示例是str()
函数。标准库通常遵循一种模式,即对一对getter/setter函数使用相同的函数名-str
至于打字是否工作量太大,是否值得——这似乎是一个奇怪的问题!如果您需要让客户端访问某些信息,请提供一个getter。如果你不开发,那么如果你正在开发COM组件,那么它是非常受欢迎的。 < P>我认为,在C++中提供访问器比C语言更重要。p>
C++对属性没有内置支持。在C#中,您可以将公共字段更改为属性,而无需更改用户代码。在C++中,这是.
对于较少的类型,您可以将普通的setter/getter实现为内联方法:
class Foo
{
public:
const std::string& bar() const { return _bar; }
void bar(const std::string& bar) { _bar = bar; }
private:
std::string _bar;
};
别忘了,[edit]我似乎需要强调的是,setter需要验证参数并强制执行不变量,所以它们通常不像这里那么简单。[/编辑]
不是全部,因为需要额外的打字。由于视觉辅助给了我“封装字段”,我倾向于更频繁地使用它们
如果只在类声明中内联实现默认的setter/getter(我倾向于这样做,但更复杂的setter会移到主体中),那么这项工作就不会更复杂了
一些注意事项:
常数:
是的,getter应该是const。但是,如果按值返回,则将返回值设为常量是没有用的。对于可能复杂的返回值,您可能希望使用const&尽管:
std::string const & GetBar() const { return bar; }
Setter链接:许多开发人员喜欢这样修改Setter:
Foo & SetBar(std::string const & bar) { this->bar = bar; return *this; }
允许调用多个设置程序,例如:
Foo foo;
foo.SetBar("Hello").SetBaz("world!");
不过,这并不是一件被普遍接受的好事
<>强> >:VisualC++提供了非标准扩展,以便调用方可以再次使用属性语法。这增加了类中的腿部工作,但使调用方代码看起来更友好
<>所以,总之,有一点更多的法律,但是在C++中有一些决策。典型;)是的,GET和SET在C++世界中很流行。< P>在争论的风险下,我会在阅读“Hulub模式”时遇到一个相反的观点。这是一个非常具有挑战性的观点,但经过思考后对我来说是有意义的:
能手和二传手都是邪恶的
使用getter和setter与面向对象设计的基本原理相反:数据抽象和封装。从长远来看,过度使用getter和setter会降低代码的灵活性和可维护性。它们最终公开了类的底层实现,将实现细节锁定到类的接口中
假设您的'std::string Foo::bar'字段需要
Foo foo;
foo.SetBar("Hello").SetBaz("world!");
// A class that represents a user's bank account
class Account {
private:
int balance_; // in cents, lets say
public:
const int& GetBalance() { return balance_; }
void SetBalance(int b) { balance_ = b; }
};
class Deposit {
private:
int ammount_;
public:
const int& GetAmount() { return ammount_; }
void SetAmmount(int a) { _balance = a; }
};
void DoStuffWithAccount () {
Account a;
// print account balance
int balance = a.GetBalance();
std::cout << balance;
// deposit some money into account
Deposit d(10000);
a.SetBalance( a.GetBalance() + d.GetValue());
}
// A class that represents a user's bank account
class Account {
private:
float balance_;
public:
void Deposit(float b) { balance_ += b; }
void Withdraw(float w) { balance_ -= w; }
void DisplayDeposit(std::ostream &o) { o << balance_; }
};
void DoStuffWithAccount () {
Account a;
// print account balance
a.DisplayBalance(std::cout);
// deposit some money into account
float depositAmt = 1000.00;
a.Deposit(depositAmt);
a.DisplayBalance(std::cout);
}
class Account {
private:
// int balance_; // old implementation
float balance_;
public:
// support the old interface
const int& GetBalance() { return (int) balance_; }
void SetBalance(int b) { balance_ = b; }
// provide a new interface for the float type
const float& GetBalance() { return balance_; } // not legal! how to expose getter for float as well as int??
void SetBalance(float b) { balance_ = b; }
};
class Foo
{
public:
std::string Bar() const { return bar; }
void Bar(const std::string& bar) { this->bar = bar; }
private:
std::string bar;
};
#define GETTER(T,member) const T& Get##member() const { return member; }
#define SETTER(T,member) void Set##member(const T & value) { member = value; }
class Foo
{
public:
GETTER(std::string, bar)
SETTER(std::string, bar)
private:
std::string bar;
}
property String^ Name;
String Name{get;set;}
property String^ Name
{
String^ get();
void set(String^ newName);
}
String^ ClassName::Name::get()
{
return m_name;
}
void ClassName::Name::set(String^ newName)
{
m_name = newName;
}
class Foo{
public:
float bar() const { return _bar; }
void bar(const float& new_bar) { _bar = ((new_bar <= 1) && (new_bar >= 0))?new_bar:_bar; } // Keeps inside [0,1]
private:
float _bar; // must be in range [0,1]
};