get和set函数在C++;程序员? 我最初来自C的世界,我在学习C++。我一直在想C++中的get和SET函数。在C#中,这些工具的使用非常流行,而Visual Studio等工具通过使其易于快速实现来促进使用。然而,在C++世界中,情况似乎并非如此。

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中: 也许人们会说,这有什么意义?为什么不创建一个公共字段,然后在需要时将其作为属性;老实说,我真的不确定。我只是出于良好的实践,因为我已经看过很多次了 因为我已经习惯了,我觉得我应

以下是C#2.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,并将其设为只读/写(但对于面向公众的接口,这似乎不太好)
缺点是:

  • 打字需要时间,这真的值得努力吗?一般来说。在某些情况下,这些优势使其值得付出努力,但我的意思是,就“良好实践”而言,是吗
答复: 我为什么要选择?事实上,我离选择很近;然而,我个人的观点(这显然是有争议的)是,答案是错误的

另一方面,我选择的答案似乎对双方都有争议;我认为如果过度使用getter和setter(我的意思是,当它没有必要并且会破坏业务模型时),那么getter和setter是邪恶的,但是为什么我们不应该有一个名为
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++中有一些决策。典型;)< 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]
};