C ++实践类似于C#的只读数据成员行为

时间:2013-11-09 00:28:22

标签: c# c++ class object-oriented-analysis

我学到了一点C#,现在我正在学习C ++。在C#中,数据隐藏可以通过get和set运算符完成,使得数据成员可以通过提供“get”而不是“set”来呈现为“只读”。

这将允许类(Person)包含另一个类(Account),使得Account类的公共函数可供Person.Account的用户使用,但是用户不能直接更改Account类,因为它是只读的。

这应该在下面的代码示例中更清楚。

我的问题是,既然C ++没有提供漂亮的get / set语法,那么下面的代码是否有C ++模拟?

using System;

class Person
{
    private string _Name;
    public string Name { get { return _Name; } set { _Name = value; } }

    private Account _Account;
    public Account Account { get { return _Account; } }

    public Person()
    {
        _Name = "";
        _Account = new Account();
    }
}

class Account
{
    private decimal _Balance;
    public decimal Balance { get { return _Balance; } }

    public Account()
    {
        _Balance = 0;
    }
    public void Deposit(decimal deposit)
    {
        _Balance += deposit;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Person p = new Person();
        p.Name = "John Doe";

        // not allowed: p.Account = new Account();
        // Property or indexer 'CSharp.Person.Account' cannot be assigned to -- it is read only

        // allowed: the Account Object's public functions are available
        p.Account.Deposit(1000);

        Console.WriteLine(p.Account.Balance.ToString());
        // console says "1000"
    }
}

4 个答案:

答案 0 :(得分:3)

这些特殊成员在C#术语中称为“属性”,并且在C ++中没有直接等同于它们。您既可以将该成员设为公用,也可以将其设为私有,并定义一个getter和setter方法,但是你不会有C#的语法糖,你必须明确地调用它们。

实际上,可以在C ++中对此行为进行编码,但这很难看,详见此处:http://www.cplusplus.com/forum/general/8147/

答案 1 :(得分:2)

这两种语言存在根本脱节。您说您希望帐户是只读的,但随后您在其上调用修改函数(Deposit)。我的C ++有线大脑说这是gobbledygook。但当然,这是因为语言不同。分配意味着两种语言完全不同。在C ++中,它只是另一种修改操作。在C#中,它重新分配引用指向不同的对象。 (我想,但我实际上并没有使用C#,所以我可能错了)。

现在,我可能会离开这里,但我建议您在这个特定情况下实际上并不需要此功能。在我看来,它唯一的好处是保持Person.Account引用的对象是唯一的。因此,两个Person对象不共享相同的Account对象。但这在C ++中是不必要的。变量是对象。它们不是共享的,除非您使用工具来显式地创建它们(使用引用,指针或智能指针)。所以,你真正想要的只是一个公共成员。

如果你真的只想禁止任务,那么你就可以做到。只需删除Account的赋值运算符即可。或者,在C ++ 11之前,将其声明为private并且不提供实现。

如果我离开这里,您是否可以更加清楚自己想要实现的目标?因为,再说一次,用C ++表示你想要一个只读对象是没有任何意义的,但是你想修改它(你正在调用Deposit)。我忽略了制作余额成员mutable的可能性,但这似乎不适合这种情况。

答案 2 :(得分:1)

C ++似乎没有直接的等价物 - 它不是用类似属性的东西制作的,而C#是因为java已经实现了它。但是,和你一样,我想知道它是否完全可能并偶然发现this小宝石。基本上,它似乎是一个返回所需变量的方法 - 并将其设置为const,以便一旦拥有它就无法更改它,只有在使用该方法时才能有效地读取它访问它。因此,如果需要,可以使用类似的东西。实际上,如果你考虑它,“属性”或“getter和setter”实际上只是链接中的内容的实现 - setter有一个参数,它将局部变量设置为你想要的值,并且getter返回它的只读版本。

答案 3 :(得分:-1)

返回shared_ptr<Account>。这样,消费者可以调用Account的方法,但不能覆盖Person._account。

#include <iostream>
#include <memory>

using std::cout;
using std::endl;
using std::shared_ptr;
using std::wstring;


class Account
{
  public:
    long Amount;
};

class Person
{
  private:
    shared_ptr<Account> _account = shared_ptr<Account>(new Account());

  public:
    wstring Name;
    shared_ptr<Account> GetAccount() { return _account; }
    shared_ptr<const Account> GetAccount() const { return _account; } // a const Person has a const Account
};

int main()
{
  Person p;

  shared_ptr<Account> a = p.GetAccount();
  a->Amount = 1;                          // access p.Account
  cout << a->Amount << endl;              // print 1

  Account* b = new Account();
  b->Amount = 2;

  a.reset(b);                             // doesn't affect p.Account

  cout << p.GetAccount()->Amount << endl; // still 1
}

这是有效的,因为返回共享指针会复制它,包括原始指针。对共享容器的更改仅影响副本,但取消引用底层指针会到达原始实例。