在以下示例中,我试图通过将using Employee::showEveryDept
设置为类Designer
的私有(private)对象来隐藏最后一个子类Elayer
的private: using Employee::showEveryDept;
,
#include <iostream>
class Employee {
private:
char name[5] = "abcd";
void allDept() { std::cout << "Woo"; }
public:
void tellName() { std::cout << name << "\n"; }
virtual void showEveryDept()
{
std::cout << "Employee can see every dept\n";
allDept();
}
};
class ELayer : public Employee {
private:
using Employee::showEveryDept;
protected:
ELayer() {}
public:
using Employee::tellName;
};
class Designer : public ELayer {
private:
char color = 'r';
public:
void showOwnDept() { std::cout << "\nDesigner can see own dept\n"; }
};
int main()
{
Employee* E = new Designer;
E->showEveryDept(); // should not work
Designer* D = dynamic_cast<Designer*>(E);
D->showOwnDept();
}
但它仍在编译中,输出为-
但我已明确将其设为私有(private),请参见-ojit_code
我在这里做错了什么?
最佳答案
类成员的名称具有以下属性:
这适用于名称本身-不适用于名称所引用的任何变量或函数。可以在相同的名称中,但在不同的声明性区域中使用相同的名称来命名相同的函数或变量。
继承一个类时,派生类的声明性区域将包含基类的所有名称;但是访问权限可能会根据继承的类型而改变:尽管仅可以将成员声明为
public
,protected
或private
,但是在继承后,您可以最终获得一个没有访问权限的成员。下表是代码中名称和区域的可访问性表:
请注意,尽管
tellName
并未在Designer
中重新声明,但在所有三个类中ELayer
是如何公开的。因此,using Employee::tellName;
的tellName
是多余的,因为无论如何public
在ELayer
中本来就是ELayer
。using Employee::showEveryDept;
的showEveryDept
的作用是ELayer
对private
的访问是Foo::name
。名称查找是解决通过调用名称找到哪个名称区域组合的过程。该调用的上下文包括:
(*E)
)showEveryDept
)访问控制还考虑到:
例如,在
ELayer
的上下文中查找ELayer::showEveryDept
会找到具有访问private
的Employee
组合。但是,在
Employee::showEveryDept
的上下文中查找相同的名称将发现可以访问public
的组合*E
。无论这两个组合是否引用相同的功能,此行为都是相同的。
在不重现有关调用上下文如何转换为搜索声明性区域的规则的完整列表的情况下,用法:
`E->showEveryDept`
在
Employee
静态类型(即public
)的区域中查找名称。它不使用动态类型,因为名称查找是在编译时解析的。没有运行时访问错误-访问是编译时属性。访问检查的最后一步是将
Employee
和main()
与调用站点public
进行比较。规则是Bla::
授予对所有调用站点的访问权限,因此访问检查通过。虚拟性不取决于名称的属性,也不取决于名称的查找范围。与访问不同,虚拟化是函数的属性,而不是任何名称区域组合。
当虚拟调度处于事件状态时,调用一个函数会将调用重定向到该函数的最终替代程序。
务必从函数实现的角度考虑这一点,而不是从函数名称的角度考虑。虚拟调度和访问控制是两个完全独立的操作。
仅当虚拟函数由unqualified-id调用时,虚拟调度才处于事件状态,这意味着通过在前面命名不含
E->showEveryDept
的函数。因此,在您的代码中,
Employee
确实激活了虚拟调度。如上所述,访问检查通过,然后虚拟分派(dispatch)调用最终的替代程序,在此示例中,该替代程序恰好是virtual
中定义的主体。在您的实际示例中,由于未覆盖该函数,因此
showEveryDept
毫无意义。但是,即使您已将ELayer
重写为using
中的私有(private)函数(而不是ojit_code声明),它仍然会调用该函数主体。