c++private-inheritance

Private inheritance and returning references from functions


Now I have code below:

class Env
{
public:
   int ra(){ return a;}
   int rb(){ return b;}
private:
   int a;
   int b;
};


class CEnv: private Env
{
public:
    static Env* Instance()
    {
        CEnv* pEnv = new CEnv;
        return pEnv;
    }

};



int _tmain(int argc, _TCHAR* argv[])
{

    Env* pEnv = CEnv::Instance();
    pEnv->ra();

    return 0;
}

And it works well.Later I add some code.

class Env
{
public:
   int ra(){ return a;}
   int rb(){ return b;}
private:
   int a;
   int b;
};


class CEnv: private Env
{
public:
    static Env* Instance()
    {
        CEnv* pEnv = new CEnv;
        return pEnv;
    }

};

Env* test()
{
    CEnv *p = new CEnv;
    return p;
}

int _tmain(int argc, _TCHAR* argv[])
{

    Env* pEnv = CEnv::Instance();
    pEnv->ra();

    return 0;
}

Then VS2010 will tell out compiler error : error C2243: 'type cast' : conversion from 'CEnv *' to 'Env &' exists, but is inaccessible.

In my opinion, it's right to show the error ,because it's not as-a relationship if using private herit. But the first code pattern works well. And I wonder why ?


Solution

  • If you replace private inheritance with a private member you will get the exact same result:

    class Env
    { /* whatever */
    };
    
    class CEnv{
    private: 
        Env m;
    
    public:
        static Env *Instance()
        {
            CEnv *pEnv = new CEnv; /* memory leak */
            return &pEnv->m;
        }
    };
    

    (Forget about the memory leak as this is just for illustrative purpose.)

    Here the member is accessible because Instance() is a member of the class.

    With a non-member function:

    Env *test()
    {
        CEnv *p = new CEnv;
        return &p->m;
    }
    

    Function test() isn't a member or friend; try it :

    prog.cpp: In function 'Env* test()':
    prog.cpp:7:13: error: 'Env CEnv::m' is private
             Env m;
                 ^
    prog.cpp:20:20: error: within this context
             return &p->m;
                        ^
    

    Make it a friend if you must:

    class CEnv2 {
    private: 
        Env m;
        friend Env *::test2();
    };
    
    Env *test2()
    {
        CEnv2 *p = new CEnv2;
        return &p->m;
    }
    

    Now it compiles.