Java's final vs. C++'s const

2019-01-03 20:46发布

The Java for C++ programmers tutorial says that (highlight is my own):

The keyword final is roughly equivalent to const in C++

What does "roughly" mean in this context? Aren't they exactly the same?

What are the differences, if any?

11条回答
叼着烟拽天下
2楼-- · 2019-01-03 20:50

In C++ marking a member function const means it may be called on const instances. Java does not have an equivalent to this. E.g.:

class Foo {
public:
   void bar();
   void foo() const;
};

void test(const Foo& i) {
   i.foo(); //fine
   i.bar(); //error
}

Values can be assigned, once, later in Java only e.g.:

public class Foo {
   void bar() {
     final int a;
     a = 10;
   }
}

is legal in Java, but not C++ whereas:

public class Foo {
   void bar() {
     final int a;
     a = 10;
     a = 11; // Not legal, even in Java: a has already been assigned a value.
   }
}

In both Java and C++ member variables may be final/const respectively. These need to be given a value by the time an instance of the class is finished being constructed.

In Java they must be set before the constructor has finished, this can be achieved in one of two ways:

public class Foo {
   private final int a;
   private final int b = 11;
   public Foo() {
      a = 10;
   }
}

In C++ you will need to use initialisation lists to give const members a value:

class Foo {
   const int a;
public:
   Foo() : a(10) {
      // Assignment here with = would not be legal
   }
};

In Java final can be used to mark things as non-overridable. C++ (pre-C++11) does not do this. E.g.:

public class Bar {
   public final void foo() {
   }
}

public class Error extends Bar {
   // Error in java, can't override
   public void foo() {
   }
}

But in C++:

class Bar {
public:
   virtual void foo() const {
   }
};

class Error: public Bar {
public:
   // Fine in C++
   virtual void foo() const {
   }
};

this is fine, because the semantics of marking a member function const are different. (You could also overload by only having the const on one of the member functions. (Note also that C++11 allows member functions to be marked final, see the C++11 update section)


C++11 update:

C++11 does in fact allow you to mark both classes and member functions as final, with identical semantics to the same feature in Java, for example in Java:

public class Bar {
   public final void foo() {
   }
}

public class Error extends Bar {
   // Error in java, can't override
   public void foo() {
   }
}

Can now be exactly written in C++11 as:

class Bar {
public:
  virtual void foo() final;
};

class Error : public Bar {
public:
  virtual void foo() final;
};

I had to compile this example with a pre-release of G++ 4.7. Note that this does not replace const in this case, but rather augments it, providing the Java-like behaviour that wasn't seen with the closest equivalent C++ keyword. So if you wanted a member function to be both final and const you would do:

class Bar {
public:
  virtual void foo() const final;
};

(The order of const and final here is required).

Previously there wasn't a direct equivalent of const member functions although making functions non-virtual would be a potential option albeit without causing an error at compile time.

Likewise the Java:

public final class Bar {
}

public class Error extends Bar {
}

becomes in C++11:

class Bar final {
};

class Error : public Bar {
};

(Previously private constructors was probably the closest you could get to this in C++)

Interestingly, in order to maintain backwards compatibility with pre-C++11 code final isn't a keyword in the usual way. (Take the trivial, legal C++98 example struct final; to see why making it a keyword would break code)

查看更多
Ridiculous、
3楼-- · 2019-01-03 20:50

Let me explain what I understood with an example of switch/case statement.

The values in each case statement must be compile-time constant values of the same data type as the switch value.

declare something like below (either in your method as local instances, or in your class as static variable(add static to it then), or an instance variable.

final String color1 = "Red";

and

static final String color2 = "Green";

switch (myColor) { // myColor is of data type String
    case color1:
    //do something here with Red
    break;
    case color2:
    //do something with Green
    break;
}

This code will not compile, if color1 is a class/instance variable and not a local variable. This will compile if color1 is defined as static final (then it becomes static final variable).

When it does not compile, you will get the following error

error: constant string expression required
查看更多
The star\"
4楼-- · 2019-01-03 20:57

You have some great answers here already, but one point that seemed worth adding: const in C++ is commonly used to prevent other parts of the program changing the state of objects. As has been pointed out, final in java can't do this (except for primitives) - it just prevents the reference from being changed to a different object. But if you are using a Collection, you can prevent changes to your objects by using the static method

 Collection.unmodifiableCollection( myCollection ) 

This returns a Collection reference that gives read-access to the elements, but throws an exception if modifications are attempted, making it a bit like const in C++

查看更多
爷、活的狠高调
5楼-- · 2019-01-03 20:58

I am guessing it says "roughly" because the meaning of const in C++ gets complicated when you talk about pointers, i.e. constant pointers vs. pointers to constant objects. Since there are no "explicit" pointers in Java, final does not have these issues.

查看更多
地球回转人心会变
6楼-- · 2019-01-03 21:00

According to wikipedia:

  • In C++, a const field is not only protected from being reassigned, but there is the additional limitation that only const methods can be called on it and it can only be passed as the const argument of other methods.
  • Non-static inner classes can freely access any field of the enclosing class, final or not.
查看更多
等我变得足够好
7楼-- · 2019-01-03 21:02

Java's final works only on primitive types and references, never on object instances themselves where the const keyword works on anything.

Compare const list<int> melist; with final List<Integer> melist; the first makes it impossible to modify the list, while the latter only stops you from assigning a new list to melist.

查看更多
登录 后发表回答