开发者

C++ equivalent for java final member data

First, my latest coding is Java, and I do not want to "write Java in C++".

Here's the deal, I have to create an immutable class. It's fairly simple. The only issue is that getting the initial values is some work. So I cannot simply call initializes to initialize my members.

So what's the best way of creating such a class? And how can I expose my immutable / final properties to the outside world in C++ standards?

here's a sample class:

class Msg {
    private:
        int _rec_num;
        int _seq;
        string text;
    public:
        Msg(const char* buffer) {
            // parse the buffer and get our member here...
            // ... lots of code
   开发者_如何学运维     }

        // does this look like proper C++?
        int get_rec_num() { return _rec_num; }
    };


C++ offers some nice mechanisms to make your class immutable. What you must do is:

  • declare all your public (and maybe protected) methods const
  • declare (but not define) operator= as private

This will ensure that your objects cannot be modified after they have been created. Now, you can provide access to your now immutable data members anyway you want, using const methods. Your example looks right, provided that you make it const:

int get_rec_num() const { return _rec_num; }

EDIT: Since C++11 you can explicitly delete operator=, rather than just leave it undefined. This explicitly instructs the compiler to not define a default copy assignment operator:

Msg& operator=(const Msg&) = delete;


I'd mark your immutable member as 'const', and assign it a value in your constructor initializer list.

I'd also parse your buffer outside of the class, and pass in the string to the constructor.

Something like this:

class Msg {
  private:
    int _rec_num;
    int _seq;
    const std::string text;
  public:
    Msg(const std::string& str) :
      text(str)
    {

    }

    // does this look like proper C++?
    int get_rec_num() const { return _rec_num; }
};

// parse the buffer and get our parameter somewhere else

NB:

You should make any member functions that do not change the state of your class internals as 'const'; as this will allow you to call them with const objects.

You should avoid inluding a using std::string in header files; as anyone who includes your header has this 'using' forced upon them.


You're on the right track -- use getters for everything, and without any setters, your class is effectively immutable.

Don't forget some of the corner cases though -- you might want to declare the operator=() method as private and not implement it so someone can't override the object with the default compiler generated assignment operator, etc.


    // does this look like proper C++?
    int get_rec_num() { return _rec_num; }

You should use

    int get_rec_num() const { return _rec_num; }

(see the const which allows to call the member on const objects).


To make a variable immutable you have to use the const key word eg const int _rec_num. Const variables can only be initialised through an initialisation list, which gets called before any code in the constructor. This means that you cannot do any processing in the constructor which sets the const member variables.

You have two ways round this, first you can create another internal class which takes in a buffer and parses it into your variables. Put a const version of this into your MSG class and put this in the initialisation list:

class MsgInner
{
    public:
    int _rec_num;

    Msg(const char* buffer) {
        // Your parsing code
    }
};

class Msg
{
    public:
    const MsgInner msg;

    Msg(const char* buffer) : msg(buffer)
    { // any other code }
};

This is perhaps not so 'standard', but it's another perspective. Otherwise you can also do it as the other answers have suggested with get methods.


On Finalizers

There is none, you have to emulate it. Either by using a cleanup function or by having all your resources encapsulted in RAII classes. The compiler will place static machinery in your application to call destructors on your RAII classes --i.e., when they go out of scope the resources get released through the destructor.

On Immutability and Initialization

Generally if something is immutable and const-correct the class will have all of its members as const and the only time you get to "write" to them is when the class is initialized. However in your case that might not be possible.

I suggest you gather all your resources and initialize the class (via a non-default constructor with const members) once you have them. The other alternative (which I do not abide) is to have a mutator function that "claims" to be const correct but writes to the const values for a one-time post construction initialization.


First of all, it is possible to initialize the members efficiently and at construction time even if they were declared as const (which is neither necessary nor recommended).

I would still suggest that you split this class into two separate classes (pseudo-code):

// Msg: pure data object; copy constructible but not modifiable.
class Msg
{
public:
  Msg(int rec_num, ...)
    : rec_num_(rec_num)
    ...
  {}

  int rec_num() const
  { return rec_num_; }
  ...
private:
  // prevent copying
  Msg& operator=(Msg const&);
private:
  int rec_num_;
}; 

// MsgParser: responsible for parsing the buffer and
// manufacturing Msg's.
class MsgParser
{
public:
  static Msg Parse(char const* buffer)
  {
     ... parse ...
     return Msg(...);
  }
};

// Usage
Msg const msg = MsgParser::Parse(buffer);

This also nicely separates the concerns of holding and parsing the data into separate classes.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜