Preface
The title "The problem of reducing accessibility of subclasses over parent class functions in Java and C++" seems to be more academic, but it is indeed an issue that is easy to ignore. This article strives to elaborate on the difference between this issue in Java and C++.
First, we will introduce what is "subclasses' accessibility reduction over parent class function coverage". For inheritance, subclasses can override the "virtual functions" of the parent class - although there is no term virtual functions in Java, all Java functions can be regarded as virtual functions, because all Java functions can be overridden by subclasses. Here we only borrow the meaning of the term "virtual function" and do not dig into the details of the language. Both Java and C++ allow changing the accessibility of functions when overriding. The so-called "accessibility" is to use access control characters such as public, protected, and private to modify it to control whether the function can be accessed. Usually the order of accessibility is (since there is no concept of packages in C++, the package access control is not considered for the time being, which does not affect the discussion here):
public > protected > private
Take Java as an example:
class Base { protected void saysHello() { System.out.println("Hello in Base"); }}class Child extends Base { public void saysHello() { System.out.println("Hello in Child"); }} Note: The sayHello() function here. In the parent class Base, this function is modified using the protected access control character. And subclasses use public instead, there will be no problem. When subclasses override parent class functions, expanding accessibility is usually not a problem.
Java and C++ adopt different strategies when subclasses reduce accessibility override to parent class functions.
First, take Java as an example and look at the following code:
class Base { public void saysHello() { System.out.println("Hello in Base"); }}class Child extends Base { private void saysHello() { System.out.println("Hello in Child"); }}In the above code, there will be a compilation error on the highlighted line 8 - this code cannot be compiled at all! Java does not allow subclasses to reduce accessibility when overwriting parent class functions. As for the reasons, we can use an example to illustrate. For example, we write the following code outside the class:
Base base = new Base();base.sayHello();base = new Child();base.sayHello();
If the previous code can be compiled, there is a possibility that when base points to new Base(), sayHello() can be accessed, but when base points to new Child(), sayHello() cannot be accessed! In Java's view, this is a contradiction, and this problem should be avoided. Therefore, Java stipulates from the compiler's perspective that we cannot write the above code.
For C++, the situation is different. Let’s take a look at C++ example:
class Base {public: virtual void saysHello() { std::cout << "Hello in Base"; }}class Child : public Base {private: void saysHello() { std::cout << "Hello in Child"; }}This code is completely correct in C++. Note that the subclass here reduces accessibility when overwriting parent class functions. If you don't see any problem, then we can write the following code outside the class:
Child child;child.sayHello(); // Cannot be compiled because saysHello() is the static_cast<Base&>(child).sayHello(); // Cannot be compiled because saysHello() is public
The line 2 call fails because in Child, sayHello() is private and cannot be called externally. However, when we cast Child to Base object using static_cast, things change - for Base, sayHello() is public, so it can be called normally.
To this end, the following example can be found in the Access to virtual functions section of the C++ standard Member access control chapter:
class B {public: virtual int f();};class D : public B {private: int f();};void f() { D d; B* pb = &d; D* pd = &d; pb->f(); // OK: B::f() is public, D::f() is invoked pd->f(); // error: D::f() is private}In this regard, the C++ standard gives an explanation:
Access is checked at the call point using the type of the expression used to denote the object for which the member function is called ( B* in the example above). The access of the member function in the class in which it was defined (D in the example above) is in general not known.
There are two key points for a simple translation:
Because of this, C++ callers seem to be able to "cleverly" call functions that were originally inaccessible through some skillful transformations. A more practical example is: in Qt, QObject::event() function is public, and its subclass QWidget event() function is changed to protected. For details, you can read the relevant code of Qt.
In summary, when subclasses override parent functions, Java strictly limits that subclasses cannot narrow down function accessibility, but C++ does not have this limitation. Personally, I believe that from the perspective of software engineering, Java regulations undoubtedly have more engineering significance, and the calls of functions are more consistent. The C++ standard will significantly simplify the compiler implementation, but it is not a good reference for engineering.
PS: The official version of the C++ standard requires purchase, but the draft can be downloaded for free. The download address of the C++ standard draft can be found on the following page: https://isocpp.org/std/the-standard
Summarize
The above is the entire content of this article. I hope that the content of this article has certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support to Wulin.com.