在以下示例中,我试图通过将using Employee::showEveryDept设置为类Designer的私有(private)对象来隐藏最后一个子类Elayerprivate: 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

我在这里做错了什么?

最佳答案

类成员的名称具有以下属性:

  • 名称-不合格的标识符。
  • 声明性区域-名称在哪个类中声明的。
  • 该区域内名称的访问权限。

  • 这适用于名称本身-不适用于名称所引用的任何变量或函数。可以在相同的名称中,但在不同的声明性区域中使用相同的名称来命名相同的函数或变量。

    继承一个类时,派生类的声明性区域将包含基类的所有名称;但是访问权限可能会根据继承的类型而改变:尽管仅可以将成员声明为publicprotectedprivate,但是在继承后,您可以最终获得一个没有访问权限的成员。

    下表是代码中名称和区域的可访问性表:

    c&#43;&#43; - using-declaration不能正常工作-LMLPHP

    请注意,尽管tellName并未在Designer中重新声明,但在所有三个类中ELayer是如何公开的。因此,using Employee::tellName;tellName是多余的,因为无论如何publicELayer中本来就是ELayer
    using Employee::showEveryDept;showEveryDept的作用是ELayerprivate的访问是Foo::name

    名称查找是解决通过调用名称找到哪个名称区域组合的过程。该调用的上下文包括:
  • 调用站点,即使用该名称的范围
  • 调用中任何明确列出的范围(例如(*E))
  • 表示要访问其成员的对象的表达式(例如showEveryDept)

  • 访问控制还考虑到:
  • 调用上下文和在其中找到名称的声明性区域之间的关系。

  • 例如,在ELayer的上下文中查找ELayer::showEveryDept会找到具有访问privateEmployee组合。

    但是,在Employee::showEveryDept的上下文中查找相同的名称将发现可以访问public的组合*E

    无论这两个组合是否引用相同的功能,此行为都是相同的。

    在不重现有关调用上下文如何转换为搜索声明性区域的规则的完整列表的情况下,用法:
    `E->showEveryDept`
    

    Employee静态类型(即public)的区域中查找名称。它不使用动态类型,因为名称查找是在编译时解析的。没有运行时访问错误-访问是编译时属性。

    访问检查的最后一步是将Employeemain()与调用站点public进行比较。规则是Bla::授予对所有调用站点的访问权限,因此访问检查通过。

    虚拟性不取决于名称的属性,也不取决于名称的查找范围。与访问不同,虚拟化是函数的属性,而不是任何名称区域组合。

    当虚拟调度处于事件状态时,调用一个函数会将调用重定向到该函数的最终替代程序。

    务必从函数实现的角度考虑这一点,而不是从函数名称的角度考虑。虚拟调度和访问控制是两个完全独立的操作。

    仅当虚拟函数由unqualified-id调用时,虚拟调度才处于事件状态,这意味着通过在前面命名不含E->showEveryDept的函数。

    因此,在您的代码中,Employee确实激活了虚拟调度。如上所述,访问检查通过,然后虚拟分派(dispatch)调用最终的替代程序,在此示例中,该替代程序恰好是virtual中定义的主体。

    在您的实际示例中,由于未覆盖该函数,因此showEveryDept毫无意义。但是,即使您已将ELayer重写为using中的私有(private)函数(而不是ojit_code声明),它仍然会调用该函数主体。

    10-04 14:47