This question already has answers here:
Overriding public virtual functions with private functions in C++
(7 answers)
Changing Function Access Mode in Derived Class
(4 answers)
Closed 7 years ago.
I came from Java where it's not allowed to decrease access modifiers in derived classes. For instnace, the following is not compile in Java:
public class A{
public void foo(){ }
}
public class B extends A{
#Override
private void foo(){ } //compile-error
}
But, in C++ it's fine:
struct A {
A(){ }
virtual ~A(){ }
A(A&&){ }
public:
virtual void bar(){ std::cout << "A" << std::endl; }
};
struct B : public A{
private:
virtual void bar(){ std::cout << "B" << std::endl; }
};
int main()
{
A *a = new B;
a -> bar(); //prints B
}
DEMO
Where might it be useful? Moreover, is it safe to do so?
As you observed, the access specifier works based on the type of the pointer, not based on the dynamic type. So specifying private in B in this case simply means the functions cannot be accessed through a pointer to B. This could therefore be useful in keeping things locked down in cases where the client should not being using pointers to B (or creating B's on the stack). Basically, in cases where B's constructor is private and you create B's (and possibly other children of A) through a factory that returns a unique_ptr<A>. In this case, you could just specify all of B's methods as private. In principle this prevents the client from "abusing" the interface by dynamic casting the unique_ptr downwards and then accessing B's interface directly.
I don't really think this should be done though; it's a more Java-y approach than C++. In general if the client wants to use a derived object on the stack instead of on the heap through a base class pointer, they should be able. It gives better performance and it's easier to reason about. It also works better in generic code.
Edit: I think I should clarify. Consider the following code:
enum class Impl {FIRST, SECOND, THIRD};
unique_ptr<A> create(Impl i) {
...
}
Suppose this is the only way to create concrete instances that use A's interface. I could desire perhaps that the derived classes are pure implementation details. For instance, I could implement each of the three implementations in a different class, then later decide that two of the three can be lumped together into one class with different options, and so on. It's none of the user's business; their world is just A's interface plus the create function. But now suppose a user happens to look at the source and knows that the FIRST implementation is implemented using B. They want better performance, so they do this:
auto a = create(Impl::FIRST);
auto b = dynamic_cast<B *>(a.get());
// Use b below, potentially avoiding vtable
If a user has code like this, and you eliminate or rename the class B, their code will break. By making all of B's methods private, you make the b pointer useless to the user, ensuring that they use the interface as intended.
As I said before, I don't particularly advocate programming this way in C++. But there may be situations where you really do need the derived classes to be pure implementation details; in those cases changing the access specifier can help enforce it.
Related
I want to write a Java2Go generator, but I find it hard to express polymorphism (e.g.: formal arg is Base class, but real arg is Sub class), how do I express blow code in Go?
class Base{
public int i;
}
class Sub extends Base{
}
class Test{
public static int test(Base base){
base.i = 99;
return base.i;
}
public static void main(String [] args){
Sub sub = new Sub();
System.out.println(test(sub));
}
}
You'll need to duplicate your code or make wrappers that calls a common utility function that it'll basically be madness.
There's no elegant way to do a "function by function translation". The elegant way to do it is to write your program in a different way.
A Go program will fundamentally have to be structured differently. From years of writing object oriented code it's a hard habit to shake, but when I figure out the "Go-like" way to solve the problems it usually works out to be simpler over time.
Having proper inheritance and all that appears to save code and keep things neat and tidy, but - at least in my experience - over years of development it easily ends up like a tangled mess, or at least hard to dig into if you haven't worked with the code for a while.
Go's interfaces are much more limited, but it'll force you to keep things simpler and more "obvious". The separation between the different classes is explicit.
There are also some advantages; it's much easier to "mix" types than with inheritance after you get some experience how to do it. Another "trick" is that a type can satisfy more than one interface for example.
If you've been writing object oriented code forever then it'll take some practice getting used to the new tools. I'd suggest instead of writing a translator, just try to write some Go based tools. It'll be fun. :-)
Here's what I came up with.
When extending a class, add the parent class as a embedded struct and attach a hidden method to the child class/struct to convert back to the parent class/struct.
For functions that accept Objects, have them accept pointers to structs.
Run from start.go
File: Test.go
package Test
import (
"fmt"
)
type Base struct{
I int
}
type Sub struct {
Base
}
func (s *Sub) _toBase() *Base{
return &s.Base
}
func Test( base *Base) int{
base.I = 99;
return base.I;
}
func Main( args []string) error{
sub := Sub{}
fmt.Println(Test(sub._toBase()));
return nil
}
File: start.go
package main
import (
"so-java2go/javaStructs/Test"
"os"
)
func main(){
Test.Main(os.Args)
}
File: Test.java
class Base{
public int i;
}
class Sub extends Base{
}
class Test{
public static int test(Base base){
base.i = 99;
return base.i;
}
public static void main(String [] args){
Sub sub = new Sub();
System.out.println(test(sub));
}
}
If you just have member variables in your classes, then you can use embedding. However, this solution isn't going to extend to the case where you also want methods on your classes, which can be overridden in subclasses, because the name-collisions will prevent your Go code from compiling.
You could compile classes to a raw-memory struct with a vtable (as if you were compiling to assembler or C), but then you'd have to implement your own garbage collector. Assuming that's not what you want, you can extend the vtable idea to include methods to return the address of member variables, which will allow you to use Go interfaces as a cheap way of implementing the vtable. Here's some code, slightly compressed to reduce the appearance of the boilerplate.
package main
import "fmt"
type Base struct {
i int
}
func (b *Base) get_i() *int { return &b.i }
func NewBase() *Base { return &Base{} }
type Sub struct {
parent Base
}
func NewSub() *Sub { return &Sub{*NewBase()} }
func (s *Sub) get_i() *int { return s.parent.get_i() }
type BaseI interface {
get_i() *int
}
func test(b BaseI) int {
*b.get_i() = 99
return *b.get_i()
}
func main() {
s := NewSub()
fmt.Println(test(s))
}
Methods will need to be name-mangled, since Java allows overloading. You'll find it fun to figure out exactly which method needs to be called at a given call site, depending on the type of the object and the types of all the method arguments :)
In fact, lots of things will end up needing to be name-mangled. For example, the above code translates the class names 'Base' and 'Sub' directly, but what if I'd called one of the classes 'main', or I'd called 'Sub', 'NewBase' (which didn't appear in the original Java source, but appeared during the translation process)? Typically, translated code would look more like this to avoid these sorts of problems:
type Java_class_Base struct {
Java_member_i Java_basetype_int
}
There's plenty of other hurdles. For example, the code above translates Java int to Go int, but the two are not the same. Go's int32 is closer, but still behaves differently (for example, Java specifies what happens on overflow, but Go doesn't). This means that even a simple expression like x = x + 1 is hard to translate, since you're going to have to write your own add function to make sure the translated code behaves identically to the Java code. Another example is that every object can potentially act as a thread-reentrant lock (since it can be synchronised on). That means that you're going to have to decide how to translate that, which is going to involve having a notion of Java thread, and being able to figure out which Java thread your translated call is executing on.
Good luck! There's a lot of difficulties ahead, but it's a fun challenge to make a compiler.
I want to write a program in java that consists of three classes, A, B, and C, such that B extends A and C extends B. Each class defines an instance variable (named "x").
how can I write a method in C to access and set A's version of x to a given value, without changing B or C's version?
I tried super.x but It wasn't true.
any help?
thanks for your attention in advance
You can access A's version of x like this:
((A)this).x
as long as x wasn't declared private in class A. I've just tested it.
Note that for fields, there is no overriding (as there is for methods). Thus, for an object of class C, there will be three x fields, but two of them can't be accessed normally because they are hidden by the other field named x. But casting the object as above will allow you to get at it, if it would have been visible if not hidden.
I think it is very poor practice to declare fields of the same name in a class and its subclasses. It's confusing. It can happen legitimately if, say, you have a class A and you later change the implementation of A and add a new private field z; in that case, it may not be possible to make sure no subclasses of A already have a field z, since you don't even always know what all the subclasses are (if A is a class you've distributed publicly, for instance). I think it's for that reason that Java allows you to have fields of the same name, and why the hiding rules are the way they are, because it allows things like this to work without breaking all the other subclasses. Other than that, though, I recommend not having fields of the same name in superclasses and subclasses. Perhaps if they're all private it might be OK, though.
Do the following
public static void main(String[] args) throws Exception {
C c = new C();
System.out.println("c:" + c.x);
System.out.println("a:" + ((A)c).x);
c.changeAX();
System.out.println("c:" + c.x);
System.out.println("a:" + ((A)c).x);
}
static class A {
int x;
}
static class B extends A {
int x;
}
static class C extends B {
int x;
public void changeAX() {
((A)this).x = 4;
}
}
Fields are resolved relative to the declared type of the reference. The above prints
c:0
a:0
c:0
a:4
The field will have to have at least protected visibility.
You don't want to be hiding class members, it's bad practice because it can easily confuse anyone trying to figure out which member you are referring to.
I misread your question. You can't do what you're trying to do.
Extending classes means adding information in several layers, ultimately resulting in one object. Although there are multiple layers, this doesn't mean that the layers are separate of eachother.
The variable X will be defined at one level (probably A) and after that the other classes will use this variable (if it's declared protected), but they won't have their own copy of it. You can only access your direct superclass.
This class might give you additional access to its own superclass, but you don't have direct contact with the super-super class.
The question about access to protected member in Java was already asked and answered a lot of times, for example:
Java: protected access across packages
But I can't understand why it is implemented this way, see explanation from "Java Programming Language" (4 ed.):
"The reasoning behind the restriction is this: Each subclass inherits the contract of the superclass and expands that contract in some way. Suppose that one subclass, as part of its expanded contract, places constraints on the values of protected members of the superclass. If a different subclass could access the protected members of objects of the first subclass then it could manipulate them in a way that would break the first subclass's contract and this should not be permissible."
OK, that's clear, but consider this inheritance structure (extract from some code):
package package1;
public class A {
protected int x;
}
package package2;
public class B extends A {
public static void main(String[] args)
C subclass = new C();
subclass.x = 7; // here any constraints can be broken - ??
}
}
class C extends B {
// class which places constraints on the value of protected member x
...
}
Here subclass.x = 7 is a valid statement which still can break a C's contract.
What am I missing?
Edited (added): Maybe I should not apply the cited logic in this situation? If we were dealing with only one package, the no restrictions exist at all. So maybe direct inheritance chain is treated in simplified way, meaning that superclass must know what it is doing...
It's ultimately all about following contracts, as stated in your posted quote. If you're really worried that someone won't read the contract, then there's a defensive programming solution to all this that introduces validation on modification.
By this I mean that the code you posted can break contract; this, however, couldn't:
public class A {
private int x;
protected final void setX(int x) throws IllegalArgumentException {
if (x < 0)
throw new IllegalArgumentException("x cannot be negative");
subValidateX(x);
this.x = x;
}
/**
* Subclasses that wish to provide extra validation should override this method
*/
protected void subValidateX(int x) {
// Intentional no-op
}
}
Here, I've done three major things:
I made x private so it can only be assigned from within A (excluding things like reflection, of course),
I made the setter final which prevents subclasses from overriding it and removing my validation, and
I made a protected method that can be overridden by subclasses to provide extra validation in addition to mine to make sure that subclasses can narrow requirements on x, but not widen them to include things like negative integers since my validation already checked that.
There are lots of good resources for how to design for inheritance in Java, especially when it comes to super-defensive protect-the-contract API programming like my example above. I'd recommend looking them up on your favorite search engine.
Ultimately, though, the developer writing the subclass needs to be responsible enough to read documentation, especially when you get into interface implementation.
Inherited classes are implicitly friends with their parent. So as soon as C is inherited from B, it is actually normal that B has the vision on C's x attribute.
Since C extends B, having
C c = new C();
c.x = 1;
is, with respect to your issue, exactly the same as
B b = new C();
b.x = 1;
Java compiler doesn't consider the runtime type of the object referred to by b and c in the above code; all it sees is the declared type, which is B and C, respectively. Now, since my second example obviously must work (the code in class B is accessing its own property, after all), it follows that the first example must work as well; otherwise it would mean that Java allows you to do less on a more specific type, which is a paradox.
Coming from a Java perspective I was surprised to find that you can only override base methods that have the virtual keyword.
In Java you use the final keyword to declare that a method can't be overridden.
I had the idea in my head that you only rarely want to prohibit overriding so that someone can extend your class how they see fit.
So in C++ if you feel that someone might want to at some stage inherit from your class (maybe years later someone thinks its a cool idea) do you make all your methods virtual?
Or is there some critical reason for wanting to prohibit this in C++ that I am unaware of?
for Reference this was the experimenting i did in each language:
Java
public class Base {
void doSomething(){
System.out.println("Doing the base thing");
}
}
public class Derived extends Base {
void doSomething(){
System.out.println("Doing the derived thing");
}
public static void main(String... argv){
Base object = new Derived();
object.doSomething();
}
}
C++
class Base
{
public:
Base(void);
~Base(void);
virtual void doSomething();
};
void Base::doSomething(){
std::cout << "I'm doing the base thing\n" << std::endl;
}
class Derived :
public Base
{
public:
Derived(void);
~Derived(void);
void doSomething();
};
void Derived::doSomething(){
std::cout << "I'm doing the dervied thing" << std::endl;
}
int main(void){
Base * object = new Derived;
object->doSomething();
return 0;
}
duffymo and Als are steering you in the right direction. I just wanted to comment on one thing you said:
So in C++ if you feel that someone might want to at some stage inherit
from your class (maybe years later someone thinks its a cool idea) do
you make all your methods virtual?
From a software engineering perspective: if you don't have an immediate use for inheritance and aren't using interfaces, then I don't recommend declaring your methods virtual.
Virtual methods come with an ever so slight performance degradation. For non-critical code paths the perf impact is likely negligible. But for class methods that get invoked a lot, it can add up. The compiler can't do as much inlining and direct linkage. Instead, the virtual method to be invoked has to be looked up in the v-table array at runtime.
When someone on my coding team starts off a design conversation with "someone might want at some point later..." that's when my "future proofing" anti-pattern alarm goes off. Designing for extensibility is one thing, but "features for the future" should be put off until then.
And besides - the guy years later who thinks it's a cool idea - Let him be the one to own converting the class methods to be virtual. You'll be onto bigger projects by then anyway. :)
Yes, in C++ a class method can only be overidden if it is marked virtual in Base class.
If your class is made for inheritance and your class method is meant to provide different behaviors for Base and derived then mark the method as virtual.
Good Read:
When to mark a function in C++ as a virtual?
Yes, you'd have to make all your methods virtual.
Java took the position that everything was fair game to override by default, and that prohibiting it required action. C++ and C# take the opposite view.
You can override a method in a base-class even without virtual.
Take this little program for example:
#include <iostream>
struct A
{
void m()
{ std::cout << "A\n"; }
virtual void n()
{ std::cout << "A\n"; }
};
struct B : public A
{
void m()
{ std::cout << "B\n"; }
virtual void n()
{ std::cout << "B\n"; }
};
int main()
{
A a;
a.m();
a.n();
B b;
b.m();
b.n();
A &c = b;
c.m();
c.n();
}
The output from the program is:
A
A
B
B
A
B
As you can see, the method B::m overrides the same method in A. But that only works when using an exact instance of B. In the third case, when using a reference to the base class you need virtual to make it work.
Programmers coming from languages where virtual functions are the default tend to be surprised that C++ has the reverse choice of defaults, i.e. non-virtual is the default. Note, however, that the contract of a [concrete] virtual function is a lot harder to document and test because there are actually two different contracts involved:
the contract of all overriding functions, i.e. what the function conceptually does
the contract of what the concrete function happens to do
Documenting only one of these won't really cut it because the other half isn't clear at all. This also means that you can't glance from a specific implementation what the actual contract is (assuming you are in the not so untypical situation that the documentation is provided by the source).
are java final methods and c++ nonvirtual methods different or the same? How?
They are different.
C++ non-virtual methods are not dispatched, and do not override anything.
Java final methods are dispatched, and can override methods in their classes superclasses.
However, they are the similar in the respect that neither C++ non-virtual methods or Java final methods can be overridden. They are also similar in the sense that if you have some object whose static type is the type in question, the runtime system does not need to dispatch the method call.
To illustrate the difference, consider these two Java classes:
public class A {
public String toString() {
return "A";
}
}
public class B extends A {
public final String toString() {
return "B";
}
}
A a = ...
B b = ...
a.toString(); // could call A.toString() or B.toString() - dispatch
b.toString(); // could only call B.toString() - no dispatch required
// but it will behave the same as if dispatching had occurred.
In the C++ equivalent where B::toString() was non-virtual, I believe a.toString() could not dispatch to B::toString(). (I'm a bit rusty on my C++ ... )
(In fact, the Java JIT compiler is capable of detecting cases where virtual dispatching is not needed ... without you declaring classes or methods as final. Thus, the true purpose of final is to specify that a method shall not be overridden or a class shall not be extended ... and have the Java compiler check this for you.)
You can still declare non-virtual member functions with the same signature in inheriting classes in C++, where-as Java explicitly forbids declaring methods with the same signature in which the base class declares that method final. Virtuality in C++ just helps find the correct function to call when dealing with inheritance/polymorphism.
Example:
#include <iostream>
class Base
{
public:
void doIt()
{
std::cout << "from Base.doIt()" << std::endl;
}
};
class Child : public Base
{
public:
void doIt()
{
std::cout << "from Child.doIt()" << std::endl;
}
};
int main()
{
Base a;
a.doIt(); // calls Base.doIt()
Child b;
b.doIt(); // calls Child.doIt()
Base *c = new Base();
c->doIt(); // calls Base.doIt()
Child *d = new Child();
d->doIt(); // calls Child.doIt()
Base *e = new Child();
e->doIt(); // calls Base.doIt()
std::cin.ignore();
return 0;
}
The comparable example in Java using final will result in a compiler error:
public class Base
{
public final void doIt()
{
System.out.println("In Base.doIt()");
}
}
public class Child extends Base
{
public void doIt() // compiler error: Cannot overload the final method from Base
{
System.out.println("In Child.doIt()");
}
}
For more explanation on Polymorphism in C++, see cplusplus.com: Polymorphism
Effictively, though, both methods have similar goals: to prevent overriding of a function in the base class. They just go about it in slightly different ways.
They are very different, in fact, I would say, completely unrelated.
In C++, if a base class has a non-virtual member function, then, you can declare, in a derived class, a non-virtual member function with the same name. The effect will be that the derived class' member function will hide the base class' member function. And no virtual dispatching can occur. As in the following:
struct Base {
void foo() {
std::cout << "Base::foo called!" << std::endl;
};
};
struct Derived : Base {
void foo() {
std::cout << "Derived::foo called!" << std::endl;
};
};
int main() {
Derived d;
d.foo(); //OUTPUT: "Derived::foo called!"
Base* b = &d;
b->foo(); //OUTPUT: "Base::foo called!"
};
The above shows how the member function of the derived class hides the base class function. If you have a pointer to a base class, since the functions are non-virtual, the virtual table is not used to resolve the call and thus, the foo function from the base class will be called. The point here is that, in C++, nothing prevents you from creating another function in the Derived class with the same name (note that a different signature will still cause the hiding of all the base class' member functions with the same name). All you will get is a compiler warning telling you that the member function of the Derived class hides member function(s) of the Base class.
A final member function in Java is completely different. In Java, all member functions are virtual. So you can't turn-off the virtual dispatching like you can in C++. A final member function just means that any subsequent derived class will not be allowed (an error will occur) to declare a member function with the same name (and signature). But virtual dispatch (and thus, overriding, in the dynamically polymorphic sense) still occurs between the interface / base class that declared the original member function and the derived class that marked it as final. It is just that later overriding of the function is strictly forbidden (i.e. trying the above code with foo() marked as final in the Base class would give an error in the declaration of the Derived class, because the foo() there would not be allowed).
As you see, the two concepts are completely different.
In C++, with a non-virtual member function, virtual dispatching does not occur (thus, no "overriding" in the traditional sense) but you are allowed to have derived classes with member functions of the same name (and it can be useful sometimes in "static polymorphism").
In Java, with a final member function, virtual dispatching still occurs, but overriding in subsequent derived classes is strictly forbidden.
Using a virtual vs non-virtual function is C++ can make a performance difference, conversely there may be no performance difference in Java. In Java, marking a method as final it is purely about clarity and maintainability of code (it is not the default behaviour and relatively rarely used), and in C++ non-virtual function are the default behaviour and commonly used in part because they have better performance characteristics.
In Java, the code generated can differ based on how it is used, whereas C++ must produce for correctness at compile time.
e.g. if the JVM detects that a "virtual" method has only one or two implementations common used it can inline those methods or treat a "virtual" method with only one implementation used as if it were final.