There are already some good points in other answers, but I'd like to provide a more complete answer, addressing your questions and statements individually.
If Java doesn't provide a feature that C++ has, it means that the feature is not good, so we should prevent using it.
This has been pretty well answered: Java isn't "the good parts" of C++, nor is there any reason to think so.
In particular, though the merits of each individual C++ feature are debatable, many of the features of C++11/C++14 that are not part of Java aren't necessarily excluded because the Java designers thought they were a poor idea. As an example case, until version 8, Java didn't have lambdas, but they were introduced to C++ in the C++11 standard. Prior to Java 8, your assumption that C++ features missing from Java were missing by design because they are "not good" would have implied that lambdas as a language feature are "not good" (to the horror of LISPers everywhere, though they're probably horrified enough to hear that you apparently actually like Java). But now the Java designers have put their Stamp of Approval (TM) on lambdas, so they're now A Good Thing.
To dig a little deeper, even in Java 8, lambdas-as-closures are not as flexible as C++14's lambdas, but this may be due to JVM architecture limitations rather than a conscious decision that the more flexible approach is bad from a language-design perspective.
C++ code with C++ specific features (e.g.: friend functions, multiple inheritance) can only be maintained or reviewed by C++ programmers, but if we just write C++ like Java (without C++ language specific feature), the code can be maintained or reviewed by both C++ and Java programmers.
This is the main thing I wanted to respond to.
Broadly speaking, there may be some value to getting code reviews from programmers who aren't intimately familiar with the language you're using. They can give you valuable feedback about the clarity of your function/method names and comments, and (as your question correctly implies) if the language is similar to one or more languages they already know, they may be able to follow the basic program flow and potentially catch logic errors.
However, it is not the case that this sort of review will ever be "as good as" or "equivalent to" review from developers who actually know the language you're using. Essentially, this is because making one language look like another will typically hide subtle differences, while making one language behave like another (especially in the case of C++ and Java) may be un-idiomatic for the language and/or might still be too confusing for the reviewers.
First, let's think about what it would mean to make C++ "look like" Java. As a simple case, you can use new
to instantiate objects, just like in Java:
Foo foo = new Foo();
But objects instantiated this way use ->
instead of .
to call methods, so if you want method calls to look like Java, you must instead write:
Foo& foo = *new Foo();
But this is un-idiomatic; in particular, the memory must later be cleaned up using delete &foo
, which some experienced C++ devs might not even realize is legal code. Either way, there are funny non-Java-like symbols sprinkled throughout, so we can't quite make the language "look like" Java. (You could eliminated *new
using #define New *new
, or, worse, #define new *new
, but then you're just begging for your fellow developers to hate you.) And, as mentioned above, delete
doesn't exist in Java, so in any case (as mentioned in another answer) you can't really ever make object-usage "look" the way it does in Java without memory leaks.
But modern C++ includes smart shared pointers, which behave a lot like Java's memory-managed variable-references. So everywhere in Java that you could write Foo foo = new Foo();
, you could instead write:
std::shared_ptr<Foo> foo = std::make_shared<Foo>();
Now you're using a language feature that's actually a lot like Java's under the hood. But suddenly you have a lot to explain to non-C++ reviewers: what is this shared_ptr
stuff? What are the subtle tricky "gotchas" of make_shared
? (It uses perfect-forwarding, which has some failure cases and can lead to the "wrong" constructor being called.) Why do methods need to be called with ->
, but using .
with some methods is permitted by the compiler? (shared_ptr
has its own methods.) If the method Foo::reset(void)
exists, an unwary developer might try to call it with foo.reset()
, which (if there is only one shared pointer pointing to that instance of Foo
when the call occurs) will delete the underlying memory and nullify foo
, and Java developers aren't likely to catch this problem.
Moreover, C++ has a lot of pitfalls that are specific to the language. As best I can tell, most C++ developers learn to deal with these pitfalls by gradually developing their own idiom for "safe" C++ practices, which is often somewhat unique to them or to their development team (see for example the existing answer that mentions the Google coding practices and the comment on it saying that "Seasoned C++ veterans usually reject Google coding guidelines"). All claims that the language might be too complicated, it seems (in my experience, at least), are typically met with some variation of "well, stop using it wrong." I realize this is a highly negative view of the C++ community, and there are certainly experienced developers more willing to help out language-learners, but there does seem to be a certain defensiveness about e.g. undefined behavior (see for instance much of the discussion in my 'pitfalls' link above).
Java developers simply won't be helpful in finding and correcting these pitfalls via code review.
You may be asked to convert the code to Java some day.
It's entirely valid--commendable, even--to try to take into account what might happen to your code in the future while you're in the design phase.
But, first, this particular consideration seems like a remote possibility: code is typically either re-used as is (for instance you could plug some or all of the working C++ code into some future Java software using a JNI interface) or rewritten entirely rather than directly manually "transcribed".
And, second, you later say,
Every C++ language specific feature (e.g.: multiple inheritance) should have alternatives to be implemented in Java....
This essentially cancels out your "convert to Java" point. If software is written in idiomatic C++ and then converted to idiomatic Java, there's no reason to expect that this conversion would (or could!) be done by applying a precise one-to-one mapping of C++ features to Java features.
Code without C++ specific features is usually more maintainable.
It's not clear what you mean here, but I actually somewhat agree with part of this: unless you're very careful, and even when you are careful, C++ features can lead to maintainability problems. The C++ FQA Lite (a website critical of the language and its adherents from someone who at least appears to actually understand it fairly well) states that
... 80% of the developers understand at most 20% of the language. It is not the same 20% for different people, so don't count on them to understand each other's code.
PLEASE NOTE: If you're a C++ fan and you get to this point in my answer and feel inclined to jump down to the comments to argue that the author of the FQA doesn't actually understand C++ or is disingenuous in most of his arguments, note that (1) exactly two sentences after I cite him I acknowledge that the FQA is a very biased source, and (2) it doesn't really matter for what I'm trying to say whether or not the FQA author understands C++, and I'm not trying to bash C++, and you should read the rest of the post without assuming that I'm anti-C++ just because I've quoted the FQA. End of note.
Similarly, Linus Torvalds hates C++ for essentially this reason (warning: link involves lots of swearing, in true infamous Linus style).
Obviously, these are very biased takes on the matter, but even C++ proponents often say that you shouldn't use the entirety of the language feature-set (once again, see the Google coding guidelines; also, Bjarne Stroustrup, the creator of C++, has publicly stated, "Within C++, there is a much smaller and cleaner language struggling to get out").
So I think there's some merit to the idea that C++ features might be too easy to misuse, especially if you're coming from a Java background. Furthermore, there's merit to the idea of alleviating these problems by restricting yourself to some subset of the language.
However, deciding which subset to use based on a different language does not seem like the right approach, unless the "different language" is C, since there really is a C-like subset of the C++ language. (Linus refers to this in his rant above, and Scott Meyers even refers to this subset as a "sub-language.") Java's run-time paradigm (garbage-collected, running on a VM) is so fundamentally different from C++'s that it's not clear there are any useful lessons to draw about C++ usage from it, and as noted above, trying to draw lessons about C++ directly from Java can lead to very non-idiomatic code.
Instead, try to define your "acceptable subset" of the language on an understanding of how the language can be used idiomatically. If you want a fairly restrictive subset that still takes advantage of many of C++'s features beyond what C offers, the aforementioned Google Coding guideline might be a good place to start. Sure, you'll get developers who say that there is "no rational argument" for some of Google's restrictions, but unless you're looking to hire Alexandrescu away from his work on the D language (which itself should tell you something), that's probably okay. It's certainly better than trying to turn C++ into Java.
Another good starting-point for a set of code guidelines is the new C++ Core Guidelines, a work-in-progress by Bjarne Stroustrup and Herb Sutter.
The only other way to deal with the shortcomings of C++ is to pick a different language. It sounds like you like Java, and you think there's a chance this project might be converted into Java eventually. As noted in another answer, you could just...start with Java.
There are two reasons why you might really truly need to use something other than Java:
- You really need the run-time performance. In this case, treating C++ like it's Java probably won't actually help you, because Java-like techniques such as shared-pointers degrade your run-time performance.
- You need the software to work on an obscure platform that doesn't yet support the JVM. In this case, you are probably stuck with languages that have GCC or Clang frontends. C and C++ are obvious candidates, but you could also look into something like Rust. (Quick plug: I haven't used Rust extensively, but it looks awesome and I am eager to work on a major Rust project as soon as I can, and I think everyone considering starting a C++ project should consider Rust as an alternative.)
Every C++ language specific feature (e.g.: multiple inheritance) should have alternatives to be implemented in Java. If it doesn't, that means the design pattern or code architecture is problematic.
I've already addressed this somewhat, but I intentionally left out your second sentence.
I'm not convinced that something like constexpr
, which wouldn't make any sense in a partially-JIT language like Java, is an indication of invalid architecture. I'm more open to the idea that excessive use of template meta-programming might be more trouble than it's worth, especially now that constexpr
exists for doing compile-time function evaluation, but it's clear from the case of constexpr
that there's no design flaw if you're using it: you're simply ensuring that some calculations occur prior to even running the code, which is an awesome performance boost (see for instance this entry for The Benchmark Game's n-body problem, which outperforms every other entry except another one written in C++, and is over twice as fast as the fastest Java implementation).
volatile
, package-private class member access, reflection/introspection, finally-blocks, checked exceptions, and so on? The whole question kind of doesn't make much sense... C++ and Java are superficially similar, but ultimately very different languages.SomeObject a = previousObject;
does very different things in Java and C++. In Java it copies a reference, while in C++ it copies the object. In Java, modifications toa
would also affect the previous object. In C++, you have two separate objects.