hg_git hg_git - 2 months ago 6
C++ Question

exposing only certain methods through public inheritence

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?

Answer

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.