子类可变更从父类继承的成员的作用域违背了面向对象的封装性

时间:2023-01-02 11:23:07
一直以为为了保证封装性,父类成员的作用域是不可以被子类所扩展的。今天写测试代码时,发现以下的代码竟然可以编译通过,吓出一身冷汗。哪位高人评评看

#include <iostream>

class BaseClass
{
public:
   int x;
protected:
   int y;
};

class SubClass:public BaseClass
{
public :
   BaseClass::y;  // 在此将父类的保护成员变成了公共成员
protected:
   BaseClass::x;
};

int main()
{
   SubClass obj;
   obj.y = 10;
   printf("%d",obj.y);
   return 0;
}

14 个解决方案

#1


public : 
  BaseClass::y;  // 在此将父类的保护成员变成了公共成员 

这是不可能的……

#2


我在vc6.0和vs2008中测试居然都成功,惊!C++ Primer上说在private和protected继承下,派生类可以恢复继承成员的访问级别,但不能使访问级别比基类中原有的更严格或更宽松。这里尽然可以放宽基类成员的访问级别,茫然!期待~~

#3


引用 2 楼 CARL_SEN 的回复:
我在vc6.0和vs2008中测试居然都成功,惊!C++ Primer上说在private和protected继承下,派生类可以恢复继承成员的访问级别,但不能使访问级别比基类中原有的更严格或更宽松。这里尽然可以放宽基类成员的访问级别,茫然!期待~~


还有这等事儿?
不过楼主的可是公有继承。

私有和保护继承的方式下,我认为吧,就算可以放宽访问级别的话,我觉得可以视为派生类新定义的成员,与基类的同名成员无关,而且,外部可访问的,也只是这个类的这个成员罢了。

#4


而在VC# 2008中,子类恢复基类保护成员的做法会引发编译时异常的。

#5



class SubClass:public BaseClass 

public : 
  BaseClass::y;  // 在此将父类的保护成员变成了公共成员 
protected: 
  BaseClass::x; 
}; 

上述代码中的BaseClass::y; 并没有将父类的保护成员编程公共成员。请看:
子类可变更从父类继承的成员的作用域违背了面向对象的封装性
从上图中可以看到y在SubClass中仍然是protected的。

请看看这篇文章,即使是基类中私有成员,也有办法可以在子类对其进行访问:
http://blog.csdn.net/pathuang68/archive/2009/04/20/4096088.aspx
见其中的红色字体提醒部分。
所以其实也没有什么啦。

#6


5L观点更正:
经过反复试验,楼主的发现是正确的!
很有意思!

下面的观点维持原来的判断:
请看看这篇文章,即使是基类中私有成员,也有办法可以在子类对其进行访问: 
http://blog.csdn.net/pathuang68/archive/2009/04/20/4096088.aspx 
见其中的红色字体提醒部分。

#7


你在public下用using Base::x再试下能编译过去么

#8


引用 3 楼 hikaliv 的回复:
引用 2 楼 CARL_SEN 的回复:
我在vc6.0和vs2008中测试居然都成功,惊!C++ Primer上说在private和protected继承下,派生类可以恢复继承成员的访问级别,但不能使访问级别比基类中原有的更严格或更宽松。这里尽然可以放宽基类成员的访问级别,茫然!期待~~ 
 

还有这等事儿? 
不过楼主的可是公有继承。 

私有和保护继承的方式下,我认为吧,就算可以放宽访问级别的话,我觉得可以视为派生类新定义的成员,与基类的同名…

如果是这样,那就更奇怪了。也就是说SubClass中会有两个y,一个是从BaseClass继承来的,一个是SubClass自己的一个与基类同名的y,那如果在SubClass中引用y的时候,岂不会产生二义性?

#9


引用 7 楼 pengzhixi 的回复:
你在public下用using Base::x再试下能编译过去么

如果7L兄弟说的是下面这样的话:

class SubClass : public BaseClass 

public : 
  using BaseClass::y; 
protected: 
  BaseClass::x;
}; 

编译和运行也是OK的。

#10


谢谢LZ的发现,先收藏了再说。

#11


请看看这篇文章,即使是基类中私有成员,也有办法可以在子类对其进行访问: 
http://blog.csdn.net/pathuang68/archive/2009/04/20/4096088.aspx 
见其中的红色字体提醒部分。
----------------------------------------------------------------------------
这是从内存上直接访问,同样的,只要愿意,我们还可以访问到当前线程栈空间的任意一个地址的值。
但这样的访问方式和C++的语义本身已经没什么关系了呀

#12


请朋友们用别的编译器试试,看看是个什么结果。前几天将RHEL AS4删了,还没重装:)

#13


引用 4 楼 hikaliv 的回复:
而在VC# 2008中,子类恢复基类保护成员的做法会引发编译时异常的。


我不知道4楼的有没有亲自动手试过,我自己在vs2008和linux下的gcc测试都是可以正确运行的,就算用了私有继承,结果仍然是一样。

#14


有请高手!

#1


public : 
  BaseClass::y;  // 在此将父类的保护成员变成了公共成员 

这是不可能的……

#2


我在vc6.0和vs2008中测试居然都成功,惊!C++ Primer上说在private和protected继承下,派生类可以恢复继承成员的访问级别,但不能使访问级别比基类中原有的更严格或更宽松。这里尽然可以放宽基类成员的访问级别,茫然!期待~~

#3


引用 2 楼 CARL_SEN 的回复:
我在vc6.0和vs2008中测试居然都成功,惊!C++ Primer上说在private和protected继承下,派生类可以恢复继承成员的访问级别,但不能使访问级别比基类中原有的更严格或更宽松。这里尽然可以放宽基类成员的访问级别,茫然!期待~~


还有这等事儿?
不过楼主的可是公有继承。

私有和保护继承的方式下,我认为吧,就算可以放宽访问级别的话,我觉得可以视为派生类新定义的成员,与基类的同名成员无关,而且,外部可访问的,也只是这个类的这个成员罢了。

#4


而在VC# 2008中,子类恢复基类保护成员的做法会引发编译时异常的。

#5



class SubClass:public BaseClass 

public : 
  BaseClass::y;  // 在此将父类的保护成员变成了公共成员 
protected: 
  BaseClass::x; 
}; 

上述代码中的BaseClass::y; 并没有将父类的保护成员编程公共成员。请看:
子类可变更从父类继承的成员的作用域违背了面向对象的封装性
从上图中可以看到y在SubClass中仍然是protected的。

请看看这篇文章,即使是基类中私有成员,也有办法可以在子类对其进行访问:
http://blog.csdn.net/pathuang68/archive/2009/04/20/4096088.aspx
见其中的红色字体提醒部分。
所以其实也没有什么啦。

#6


5L观点更正:
经过反复试验,楼主的发现是正确的!
很有意思!

下面的观点维持原来的判断:
请看看这篇文章,即使是基类中私有成员,也有办法可以在子类对其进行访问: 
http://blog.csdn.net/pathuang68/archive/2009/04/20/4096088.aspx 
见其中的红色字体提醒部分。

#7


你在public下用using Base::x再试下能编译过去么

#8


引用 3 楼 hikaliv 的回复:
引用 2 楼 CARL_SEN 的回复:
我在vc6.0和vs2008中测试居然都成功,惊!C++ Primer上说在private和protected继承下,派生类可以恢复继承成员的访问级别,但不能使访问级别比基类中原有的更严格或更宽松。这里尽然可以放宽基类成员的访问级别,茫然!期待~~ 
 

还有这等事儿? 
不过楼主的可是公有继承。 

私有和保护继承的方式下,我认为吧,就算可以放宽访问级别的话,我觉得可以视为派生类新定义的成员,与基类的同名…

如果是这样,那就更奇怪了。也就是说SubClass中会有两个y,一个是从BaseClass继承来的,一个是SubClass自己的一个与基类同名的y,那如果在SubClass中引用y的时候,岂不会产生二义性?

#9


引用 7 楼 pengzhixi 的回复:
你在public下用using Base::x再试下能编译过去么

如果7L兄弟说的是下面这样的话:

class SubClass : public BaseClass 

public : 
  using BaseClass::y; 
protected: 
  BaseClass::x;
}; 

编译和运行也是OK的。

#10


谢谢LZ的发现,先收藏了再说。

#11


请看看这篇文章,即使是基类中私有成员,也有办法可以在子类对其进行访问: 
http://blog.csdn.net/pathuang68/archive/2009/04/20/4096088.aspx 
见其中的红色字体提醒部分。
----------------------------------------------------------------------------
这是从内存上直接访问,同样的,只要愿意,我们还可以访问到当前线程栈空间的任意一个地址的值。
但这样的访问方式和C++的语义本身已经没什么关系了呀

#12


请朋友们用别的编译器试试,看看是个什么结果。前几天将RHEL AS4删了,还没重装:)

#13


引用 4 楼 hikaliv 的回复:
而在VC# 2008中,子类恢复基类保护成员的做法会引发编译时异常的。


我不知道4楼的有没有亲自动手试过,我自己在vs2008和linux下的gcc测试都是可以正确运行的,就算用了私有继承,结果仍然是一样。

#14


有请高手!