简体   繁体   English

仅通过公共继承暴露某些方法

[英]exposing only certain methods through public inheritence

I have a base class, say Employee with some methods on it. 我有一个基类,说Employee有一些方法。 I will later derive some child classes like Manager , Developer , Designer etc which are employees as well (because of inheritence). 我稍后会派出一些子类,如ManagerDeveloperDesigner等,这些子类也是员工(因为继承)。 Now say the code looks like - 现在说代码看起来像 -

#include <iostream>
#include <vector>

class Employee{
    private : char name[5] = "abcd";
              void allDept(){ std::cout<<"Woo"; }

    public: void tellName(){std::cout << name << "\n"; }
            void showEveryDept(){std::cout<< "Employee can see every dept\n"; 
                                 allDept(); }
            virtual ~Employee() {}
};

class Manager: public Employee{
    private : char dept[5] = "aaaa";
    public: void showOwnDept(){std::cout<< "Manager can see own dept\n";}
};

class Designer: public Employee{
    private : char color = 'r';
    public: void showOwnDept(){std::cout<< "Designer can see own dept\n";}
};

int main(){

    Employee *E = new Designer;

    E->showEveryDept();

    // E->showOwnDept(); // will not work, but can be casted dynamically and even statically if sure, to call it!

    Designer* D = dynamic_cast<Designer*>(E);

    D->showOwnDept();
}

So what we can see here is that I can cast it and using polymorphism, point the base class pointer to derived class object and still call base class accessible methods on child class. 所以我们在这里看到的是我可以使用多态,将基类指针指向派生类对象,并仍在子类上调用基类可访问方法。 Also to call child class methods from child class, I can dynamically cast it back, right. 另外,要从子类调用子类方法,我可以动态地将其转换回来。

But now what I want to do is, hide one of the public class member from child class invocation, so that child class isn't able to call it but base class object can. 但是现在我想要做的是,从子类调用中隐藏一个公共类成员,这样子类不能调用它,但是基类对象可以。 Take the example of showEveryDept() , which can be invoked by both child as well parent classes. showEveryDept()为例,它可以由子类和父类调用。 But since Designer and Manager have been allocated their dept, I don't want them to access this function. 但是由于Designer和Manager已经分配了他们的部门,我不希望他们访问这个功能。

I tried a very hacky way to solve this, by writing another layer of class b/w Employee class and it's child, like this - 我尝试了一种非常hacky的方法来解决这个问题,通过编写另一层类的b / w Employee类和它的孩子,就像这样 -

class Employee{
    private : char name[5] = "abcd";
              void allDept(){ std::cout<<"Woo"; }

    public: void tellName(){std::cout << name << "\n"; }
            void showEveryDept(){std::cout<< "Employee can see every dept\n";
                                 allDept();}
            virtual ~Employee() {}
};

class ELayer: private Employee{
    private: using Employee::showEveryDept;
    private: using Employee::tellName;
};

class Manager: public ELayer{
    private : char dept[5] = "aaaa";
    public: void showOwnDept(){std::cout<< "Manager can see own dept\n";}
};

class Designer: public ELayer{
    private : char color = 'r';
    public: void showOwnDept(){std::cout<< "Designer can see own dept\n";}
};

int main(){
    Employee *E = new Designer;
    E->showEveryDept();
    // E->showOwnDept(); // will not work, but can be casted dynamically
                      // and even statically if sure, to call it!
    Designer* D = dynamic_cast<Designer*>(E);
    D->showOwnDept();
}

but as clever as it looks, it doesn't works - 但是看起来很聪明,它不起作用 -

 prog.cc: In function 'int main()': prog.cc:27:23: error: 'Employee' is an inaccessible base of 'Designer' Employee *E = new Designer; 

So what are my options here? 那么我的选择是什么? One stupid way would be to make that function virtual , but again child classes aren't forced to override it, and if they forgot to declare it, it will call parent's function? 一种愚蠢的方法是将该函数设置为虚拟,但是子类不会被强制覆盖它,如果它们忘了声明它,它会调用父函数吗?

But now what I want to do is, hide one of the public class member from child class invocation, so that child class isn't able to call it but base class object can. 但是现在我想要做的是,从子类调用中隐藏一个公共类成员,这样子类不能调用它,但是基类对象可以。

Inheritance is based on the Liskov substitution principle . 继承基于Liskov替换原则 In a nutshell, anywhere I use a Base* I should be able to use a Derived* and everything should work equivalently. 简而言之,在任何我使用Base*我应该能够使用Derived*并且一切都应该等效。 You want to violate that concept here by making a base class operation ill-formed for your derived class. 您希望通过使派生类的基类操作格式错误来违反该概念。 That means your abstraction is wrong. 这意味着你的抽象是错误的。

Moreover, such a thing is pointless anyway. 而且,无论如何,这样的事情毫无意义。 You can't implement such a mechanism dynamically, and if you implemented it statically so that: 您无法动态实现此类机制,并且如果您静态实现它,以便:

Derived d;
Base* b = &d;

b->foo(); // OK
d.foo();  // error

I could always just do: 我总能做到:

static_cast<Base&>(d).foo(); // OK, just verbose

You probably want a second branch of your hierarchy: 您可能需要层次结构的第二个分支:

struct Base { };
struct SpecialDerived : Base { void foo(); };
struct NormalDerived : Base { };

Now only SpecialDerived can call foo() , but still every SpecialDerived is a Base and every NormalDerived is a Base , and everything just works smoothly. 现在只有SpecialDerived可以调用foo() ,但是每个SpecialDerived仍然是一个Base ,每个NormalDerived都是一个Base ,一切都运行得很顺利。

It sounds to me like you may need to rethink your inheritance hierarchy a little. 听起来像你可能需要重新考虑你的继承层次结构。 If classes derived from Employee shouldn't be able to call showEveryDept() , then that indicates to me that showEveryDept() shouldn't be part of Employee to begin with. 如果派生自Employee类不能调用showEveryDept() ,那么这表明showEveryDept()不应该成为Employee一部分。 By attempting to remove a method from the Employee public interface in its derived classes, you're breaking the subtype relationship. 通过尝试从派生类中的Employee公共接口中删除方法,您将破坏子类型关系。 If B lacks some of the behavior that makes something an A , then B is not an A and shouldn't derive from A . 如果B缺少使某些东西成为A某些行为,则B 不是 A而不应该从A派生。

Perhaps you should add another class that derives from Employee and move showEveryDept() to that class. 也许您应该添加另一个派生自Employee类,并将showEveryDept()移动到该类。 Or perhaps simply allowing Manager and Designer to call showEveryDept() is the appropriate behavior. 或者简单地允许ManagerDesigner调用showEveryDept()是合适的行为。 I can't say without knowing more about your goals. 如果不了解你的目标,我不能说。

Another option would be to use using declarations in the child, along with private inheritance, to selectively decide what you may access from it. 另一种选择是使用using声明的孩子,与私有继承一起,选择性地决定你可以访问它。 This is more flexible than the virtual alternative, and lacks any extra overhead. 这比virtual替代方案更灵活,并且没有任何额外开销。 Plus, it can "transform" public access into protected access, for instance. 此外,它可以将公共访问“转换”为受保护的访问。

class Employee
{
    private:
        char name[5] = "abcd";

        void allDept()
        {
            std::cout << "Woo";
        }

    public:
        void tellName()
        {
            std::cout << name << "\n";
        }

        void showEveryDept()
        {
            std::cout << "Employee can see every dept\n";
            allDept();
        }

        virtual ~Employee() {}
};

class Designer : private Employee
{
    private:
        char color = 'r';

    public:
        using Employee::tellName();

        void showOwnDept()
        {
            std::cout<< "Designer can see own dept\n";
        }
};

Now, you can call Desginer::tellName() and Designer::showOwnDept() , but Designer::showEveryDept() is private! 现在,您可以调用Desginer::tellName()Designer::showOwnDept() ,但Designer::showEveryDept()是私有的! The drawback, however, is that you may no longer convert a Designer* to an Employee* from outer code. 但是,缺点是您不能再从外部代码将Designer*转换为Employee* You could add a method in Employee to do exactly that. 您可以在Employee添加一个方法来做到这一点。 However, you should remember to do using Employee::as_employee in derived classes. 但是,您应该记得在派生类中using Employee::as_employee

class Employee
{
    public:
        Employee& as_employee()
        {
            return *this;
        }

        const Employee& as_employee() const
        {
            return *this;
        }
};

Anyways, you should ask yourself whether this is really the best intended design and you really need to do this, or if it would be better to just have a (optionally pure) virtual function showDept() in Employee that derived classes may (or must, if pure) override. 无论如何,你应该问自己这是否真的是最好的预期设计,你真的需要这样做,或者如果在Employee中有一个(可选纯的)虚拟函数showDept()更好,派生类可能(或必须) ,如果纯粹的覆盖。

Edit : From a comment of yours I read in another answer, I can easily conclude that your problem is that you are not understanding that the base class, Employee is not to be used as some sort of "unassigned employee" placeholder. 编辑 :从你的评论我读到另一个答案,我可以很容易地得出结论,你的问题是你不明白基类, Employee不会被用作某种“未分配的员工”占位符。 Put this way: A designer is an employee, and an unassigned employee is an employee, but a designer is not an unassigned employee. 这样:设计师是员工,未分配的员工是员工,但设计师不是未分配的员工。 So, it's best to restructure your code. 因此,最好重新构建代码。 Anyways, I'm leaving the above solution for the purposes of completeness. 无论如何,为了完整起见,我将离开上述解决方案。

Hiding methods of parent classes (either directly or indirectly) in a child is not the best way to tackle this problem. 在子女中隐藏父类(直接或间接)的方法并不是解决此问题的最佳方法。 For example, what if the child of the child wants to gain back the hidden functionality ? 例如,如果孩子的孩子想要获得隐藏的功能怎么办? It is a mess. 这是一团糟。

One way to achieve what you need is to model it: Whether an employee can or cannot see all departments is an "attribute" of the employee. 实现您所需要的一种方法是对其进行建模:员工是否能够看到所有部门是员工的“属性”。 So, you can add a bool property "CanShowEveryDept", decide its default value in parent according to your functional requirements, and set it properly in each child class constructor. 因此,您可以添加bool属性“CanShowEveryDept”,根据您的功能要求在父级中确定其默认值,并在每个子类构造函数中正确设置它。

class Employee
{
protected:
    bool CanShowEveryDept;
public:
    Employee()
    {
        CanShowEveryDept = true;
    }


public:
    void showEveryDept()
    {
        if (!CanShowEveryDept)
            return;

        std::cout << "Employee can see every dept\n";
        allDept();
    }
};

class Designer : private Employee
{
public:
    Designer()
    {
        CanShowEveryDept = false;
    }
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM