-1

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 ?

David Brossard
  • 13,584
  • 6
  • 55
  • 88
xingfu0539
  • 62
  • 6
  • 4
    "_And it works well_" No it doesn't. – curiousguy Jan 12 '16 at 08:44
  • In my vs2010, it works well indeed. And which error shows in your computer ? – xingfu0539 Jan 12 '16 at 08:46
  • *Where* do you get the error? On what line? Can you please mark it out with a comment? I don't even see anywhere you use use pointers to `CEnv`. – Some programmer dude Jan 12 '16 at 08:47
  • I use no pointer but the quote.The error occures in Env& test() { static CEnv env; return env; //compiler error here } – xingfu0539 Jan 12 '16 at 08:51
  • 2
    `static Env& Instance() { CEnv env; return env; }` - you can't return a reference to an automatic stack-hosted variable and expect it to work reliably. That's undefined behaviour, and will be covered in any introductory C++ book. Hundreds of existing SO Q&A discuss this: search for *"C++ return reference to local variable"*. Note that making the function `static` does ***not*** make the variable `static`. – Tony Delroy Jan 12 '16 at 08:51
  • By definition, private inheritance isn't accessible to other functions, just like private members. – curiousguy Jan 12 '16 at 09:03
  • Thansk for your suggestion and now i fixed code errors.And my question is why the second code pattern have errors ? @ Tony D – xingfu0539 Jan 12 '16 at 09:05
  • 1
    @xin Read [ask]. This is not a discussion forum. You can't post follow-up questions in an existing question, let alone the comments on an existing question... – dandan78 Jan 12 '16 at 09:06
  • I can not @ somebody ,so i just write my comment below, so don't mind, and thanks for all of your answers. When curisousguy say "By definition, private inheritance isn't accessible to other functions, just like private members", I agree with it, but why the first code pattern works and no error. I think it is conflict. – xingfu0539 Jan 12 '16 at 09:09
  • 1
    You shouldn't remove the original code from your question - now nobody knows what you were asking or why existing comments and answers discuss the mistakes you had made. – Tony Delroy Jan 12 '16 at 09:11
  • OK, i am so sorry , and i will learn "how to ask" ,and will not make this mistake, thakns. – xingfu0539 Jan 12 '16 at 09:17
  • @TonyD Comments have a time and edit history is accessible, but perhaps after a significant edit one should post a big comment warning "_________ question edited NOW _________" – curiousguy Jan 12 '16 at 09:19

3 Answers3

1

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.

curiousguy
  • 8,038
  • 2
  • 40
  • 58
0

Your Instance() method is broken, you should only have 1 static object:

static Env* Instance()
{
    static CEnv instance;
    return &instance;
}

Or, reference case:

static Env& Instance()
{
    static CEnv instance;
    return instance;
}
Hatted Rooster
  • 35,759
  • 6
  • 62
  • 122
  • Thanks, and i fixed my code just now. And now i wonder why private inheritance could access functions of parent class. In 2rd code pattern ,it is not allowed in test() function ,so i think it is right, but in Instance() function , it works. – xingfu0539 Jan 12 '16 at 09:13
  • Because the derived constructor always has access to the base class' constructor. – Hatted Rooster Jan 12 '16 at 09:14
  • @JameyD "the derived constructor always has access to the base class' constructor" hug? – curiousguy Jan 12 '16 at 09:20
  • I'm sorry ,i still confused.There is no explicit constructor but default constructor. Instance() function is just an ordinary function. So i still don't understand.Could you explain it more clearly? – xingfu0539 Jan 12 '16 at 09:26
  • @xingfu0539 No, `Instance()` is a member function. – curiousguy Jan 12 '16 at 09:30
0

Private inheritance is an "is-a" relationship that is a secret to everyone except the inheriting class itself.

Inside your CEnv class, the inheritance is "known" (private inheritance would be mostly useless if the inheriting class weren't allowed to know about it).

Thus, the conversion from CEnv* to Env* in CEnv::Instance is valid, since it's CEnv that does the conversion.

The test function is not a member of CEnv, so from its point of view the conversion isn't allowed.

molbdnilo
  • 64,751
  • 3
  • 43
  • 82