【问题标题】:Private inheritance and returning references from functions私有继承和从函数返回引用
【发布时间】:2016-01-12 08:42:42
【问题描述】:

现在我有以下代码:

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;
}

而且效果很好。稍后我添加一些代码。

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;
}

然后VS2010会告诉编译器错误: 错误 C2243:“类型转换”:存在从“CEnv *”到“Env &”的转换,但无法访问。

在我看来,显示错误是正确的,因为如果使用私有继承,它就不是一种关系。 但是第一个 Code Pattern 运行良好。 我想知道为什么?

【问题讨论】:

  • "而且效果很好"不,它没有。
  • 在我的vs2010中,确实运行良好。您的计算机中显示了哪个错误?
  • static Env& Instance() { CEnv env; return env; } - 您不能返回对自动堆栈托管变量的引用并期望它能够可靠地工作。这是未定义的行为,将在任何介绍性 C++ 书籍中介绍。现有的数百个 SO Q&A 讨论了这一点:搜索 “C++ 返回对局部变量的引用”。请注意,创建函数static 确实 会创建变量static
  • @xin 阅读How to Ask。这不是一个讨论论坛。您不能在现有问题中发布后续问题,更不用说现有问题的 cmets...
  • 你不应该从你的问题中删除原始代码 - 现在没有人知道你在问什么或者为什么现有的 cmets 和答案会讨论你所犯的错误。

标签: c++ private-inheritance


【解决方案1】:

如果您将私有继承替换为私有成员,您将得到完全相同的结果:

class Env
{ /* whatever */
};

class CEnv{
private: 
    Env m;

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

(忘记内存泄漏,这只是为了说明目的。)

这里的成员是可访问的因为Instance()是该类的成员

使用非成员函数:

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

函数test() 不是会员或朋友; 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;
                    ^

如果必须,请加为好友:

class CEnv2 {
private: 
    Env m;
    friend Env *::test2();
};

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

现在it compiles

【讨论】:

    【解决方案2】:

    你的Instance()方法坏了,你应该只有1个static对象:

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

    或者,参考案例:

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

    【讨论】:

    • 谢谢,我刚刚修复了我的代码。现在我想知道为什么私有继承可以访问父类的功能。在第二个代码模式中,test() 函数中是不允许的,所以我认为它是正确的,但是在 Instance() 函数中,它可以工作。
    • 因为派生构造函数总是可以访问基类的构造函数。
    • @JameyD "派生构造函数总是可以访问基类的构造函数" 拥抱?
    • 对不起,我还是很困惑。没有显式构造函数,只有默认构造函数。 Instance() 函数只是一个普通函数。所以还是不明白,能不能解释的更清楚一点?
    • @xingfu0539 不,Instance() 是成员函数。
    【解决方案3】:

    私有继承是一种“is-a”关系,除了继承类本身之外,对所有人来说都是秘密。

    在您的CEnv 类中,继承是“已知的”(如果不允许继承类知道私有继承,那么私有继承将几乎无用)。

    因此,CEnv::Instance 中从 CEnv*Env* 的转换是有效的,因为进行转换的是 CEnv

    test 函数不是CEnv 的成员,因此从它的角度来看是不允许转换的。

    【讨论】:

      猜你喜欢
      • 2011-10-30
      • 2011-07-04
      • 2020-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多