34

Locking down state is great. In C# you can ensure that a field doesn't change it's value/reference once the constructor completes by declaring it as readonly.

class Foo
{
    private readonly string _foo;

    public Foo() {
        _foo = "Unchangeable";
    }

    public void ChangeIt() {
        _foo = "Darn";        // compiler error
    }
}

Can I do the same thing with C++? If so, how? If not, why not?

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
  • @NicolBolas you closed this as a dupe yet it came first and has four times as many views as the supposed original. – Drew Noakes Jun 05 '19 at 04:38
  • The target question has much better answers. And that matters more. The accepted answer here is a link-only answer that mentions a keyword, as though that explained everything. The accepted answer there goes into detail about what `const` is and how to use it. – Nicol Bolas Jun 05 '19 at 04:39

7 Answers7

21

That would be const. Note that this keyword means a couple of different things in different contexts.

jackrabbit
  • 5,525
  • 1
  • 27
  • 38
  • Both links are pretty good (pre/post edit.) Thanks very much. – Drew Noakes May 16 '11 at 16:57
  • Both describe basically the same thing, but the new one is much less negative about the whole thing. Since I like const, I prefer linking to the neutral description ;) If you like my answer, perhaps you could accept it? – jackrabbit May 16 '11 at 17:01
  • Patience my friend. I generally let a question sit for a while before accepting it to see what other answers surface. Once a question is answered it tends to garner less attention from passers-by. Enjoy the suspense. – Drew Noakes May 16 '11 at 18:11
  • Good strategy - never thought of that (haven't needed to, since I haven't asked a question yet). – jackrabbit May 16 '11 at 21:04
  • Consider also: const_cast, which allows you to add or remove const at runtime. – Andrew Jun 11 '16 at 08:30
  • 21
    This answer is wrong. C++'s `const` is equal to C#'s `const` keyword, not `readonly`. You cannot asign a value to a `const` field in the constructor itself in C++, only if you use an initialization list. This renders C++ `const` members useless, because move and copy assignments don't have anything like an initialization list. – oddRaven Oct 15 '16 at 12:23
  • Are you sure move and copy constructors don't have an initialization list? "const and volatile semantics of an object under construction don't kick in until the most-derived constructor completes." It doesn't say what kind of constuctor, move and copy const. are the same: https://en.cppreference.com/w/cpp/language/initializer_list – Chris Smith Jun 24 '18 at 08:18
  • As @oddRaven said this answer is wrong! Const in C++ is equivalent to C# const not readonly. – Огњен Шобајић Jul 03 '19 at 22:10
  • Christian Rau has the correct answer. There is no equivalent. As seen in Qt (C++), they implement private class pattern using something called a D-pointer to get around this issue. – Kale_Surfer_Dude Jul 24 '20 at 03:17
20
class Foo
{
private:
    const string _foo;
public:
    Foo() : _foo("Unchangeable")
    {
    }
    void ChangeIt()
    {
        _foo = "Darn";        // compiler error
    }
};
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • 2
    The note about identifiers starting with an underscore isn't 100% correct. – dalle May 16 '11 at 16:45
  • 1
    @dalle, it appears you're correct - they're only reserved in the global namespace, not within the context of a class. I'll fix my answer. http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier – Mark Ransom May 16 '11 at 16:47
  • 1
    +1, but sorry for being picky. – dalle May 16 '11 at 16:51
  • 2
    @dalle, no need to apologize. Every time I get corrected I learn something, and I appreciate it. – Mark Ransom May 16 '11 at 16:56
15

There is no such thing directly. You can use a private field with a public getter (but no setter). But that would only apply to other classes calling your code. Foo always has full acces to its members. But since you are the implementer of Foo, this is no real problem.

Christian Rau
  • 45,360
  • 10
  • 108
  • 185
8

It was not immediately clear to me after reading the accepted answer that to make exact equivalent of readonly keyword you need to declare the member like this:

class Y
{
public:
     void mutate() { x = 7; } // not const member
     int x;
};

class X
{
private:
    Y * const member; // this only makes the pointer to Y const, 
                      // but you can still modify the object itself
public:
    X(Y *m) : member(m) {}

    void f() { member->mutate(); }
};

Hope this helps.

serine
  • 1,338
  • 14
  • 24
3

A reference in C++ is not rebindable, so it's equivalent to a C# readonly reference.

BCoates
  • 1,508
  • 10
  • 16
  • The reference cannot be changed. However, the thing the reference points to can be changed. A member `std::string &s` can be changed perfectly well and the change would propagate to everyone using it. –  May 16 '11 at 16:40
  • 1
    @delnan: C#'s readonly works the same way, a readonly StringBuilder can have its contents changed but not be bound to a different StringBuilder. – BCoates May 16 '11 at 16:45
  • No, not really. References can be changed to refer to a completely different object, while a readonly field always refer to the same thing even though this thing may change its internal state. For reference types, it may work similar enough in practice. But the difference is plainly visible with value types, which can be changed with C++ references but not with C# readonly fields. –  May 16 '11 at 16:51
  • C# readonly for value types is an entirely different thing than it is for reference types. C++ references cannot point to a different object once bound, but changing the value of an int is not pointing to a different object in C++. – BCoates May 16 '11 at 17:04
  • The point is: `x = 0;` isn't supposed to work. With C++ references, it does. With a C# readonly field, it doesn't. (But to nitpick, you're still wrong unless you consider the location - e.g. variable - the reference refers to an "object", which might be valid but isn't useful and beyond what "object" refers to in other languages.) –  May 16 '11 at 17:09
1

I had the same need as you when doing a transcription from C# to C++ and it is just a syntax error because this instruction exists in C++ ( visual C++)

Syntax : [readonly]

"The readonly C++ attribute has the same functionality as the readonly MIDL attribute. If you want to prohibit modification of a method parameter, then use the in attribute."

source : https://msdn.microsoft.com/en-us/library/45x4ky7s.aspx

source : https://msdn.microsoft.com/library/windows/desktop/aa367152

moons17
  • 11
  • 2
1

C++ has const, which does the same job as readonly in C#.

const int Constant1 = 96;    
Constant1 = 200   // Compiler Error.
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
anijhaw
  • 8,954
  • 7
  • 35
  • 36
  • Is `const` for a local variable (as this example seems to show) the same as `const` for a field, as in the original question? – Drew Noakes May 16 '11 at 18:12
  • 1
    Readonly in C# is assigned value in ctr, whereas const is compile-time known value, so they are not the same. – Огњен Шобајић Apr 27 '19 at 21:18
  • Const values (both in C++ and C#) are optimized out by compilers. Readonly are not as their values are not known ahead. – Огњен Шобајић Jul 03 '19 at 22:07
  • 1
    It doesn't do the same job as readonly in C#. Const local or field in C++ has to be initialized when it is defined. Readonly in C# doesn't have to be initialized when it is defined, it can be initialized later in a constructor. You can also only have readonly field and not local variable. Also, const in C# has to be initialized by a constant expression and known at a compile time, as @ОгњенШобајић said. – KulaGGin Jul 08 '19 at 13:05