3

I have a base class, say Employee with some methods on it. I will later derive some child classes like Manager, Developer, Designer etc which are employees as well (because of inheritence). 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. But since Designer and Manager have been allocated their dept, I don't want them to access this function.

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 -

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?

hg_git
  • 2,884
  • 6
  • 24
  • 43

4 Answers4

3

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. In a nutshell, anywhere I use a Base* I should be able to use a Derived* and everything should work equivalently. 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.

Community
  • 1
  • 1
Barry
  • 286,269
  • 29
  • 621
  • 977
2

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. By attempting to remove a method from the Employee public interface in its derived classes, you're breaking the subtype relationship. If B lacks some of the behavior that makes something an A, then B is not an A and shouldn't derive from A.

Perhaps you should add another class that derives from Employee and move showEveryDept() to that class. Or perhaps simply allowing Manager and Designer to call showEveryDept() is the appropriate behavior. I can't say without knowing more about your goals.

Jonathan Sharman
  • 636
  • 6
  • 16
  • see I cannot remodel real world relationships into something artificial just because this language dosen't allow that kind of model. Employees when not assigned something can see other dept as well, but once they're inherited to get into certain dept. , they can see their own dept. only. Maybe I lack expertise in this language, but the requirements are these only. That's why I'm asking for help to make it work. – hg_git Sep 17 '16 at 05:23
  • "Perhaps you should add another class that derives from Employee and move showEveryDept() to that class." Correct, I've actually tried that and its written even in my answer, but that doesn't plays well :/ – hg_git Sep 17 '16 at 05:24
  • 2
    Given those constraints, I would restructure your hierarchy to include something like "`UnassignedEmployee`", deriving from `Employee`. Then put your `showEveryDept()` method in that class. Edit: The difference between what I'm suggesting and what you've already tried is that `Manager` and `Designer` should not derive from `UnassignedEmployee` (or whatever you call it). – Jonathan Sharman Sep 17 '16 at 05:28
1

Another option would be to use using declarations in the child, along with private inheritance, to selectively decide what you may access from it. This is more flexible than the virtual alternative, and lacks any extra overhead. 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! The drawback, however, is that you may no longer convert a Designer* to an Employee* from outer code. You could add a method in Employee to do exactly that. However, you should remember to do using Employee::as_employee in derived classes.

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.

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. 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.

3442
  • 8,248
  • 2
  • 19
  • 41
1

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.

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;
    }
};
GeorgeT
  • 484
  • 3
  • 5