【问题标题】:Struct inheritance: implicitly public or private?结构继承:隐式公共还是私有?
【发布时间】:2014-05-25 22:08:54
【问题描述】:

我无法在一个小样本中隔离此错误以在此处进行演示,但即使错误消息是如此自相矛盾,以至于人们无需测试即可知道这是否是错误。

我有一个结构(可能是公开的)派生另一个结构,但 clang 坚持认为这是隐含的私有继承:

error: 'next' is a private member of 'base'

note: constrained by implicitly private inheritance here
struct derived_temp <key> : base <derived>

虽然 g++ 编译得很好。我只更改了类的实际名称以使消息更具可读性。代码如下所示:

template </*...*/>
struct base : //...
{
private:
    //...

public:
    template <typename I> I next(I i) const { return /*...*/; }
    //...
};

template <typename /*...*/>
struct derived_temp;

struct key { /*...*/ };

using derived = derived_temp <key>;

template <>
struct derived_temp <key> : base <derived>
{
   //...
};

我试图保持代码的形式与我的项目中的完全相同,只是更改了名称并注释掉了其中的一部分。

该错误是由于尝试在 derived 类型的临时对象上调用函数 next() 引起的。

我唯一的解释是,这可能是 clang 的一个错误(但是,我无法在小样本中重现它)迫使我改变

struct derived_temp <key> : base <derived>

更明确

struct derived_temp <key> : public base <derived>

有什么想法吗?

【问题讨论】:

  • 在不知道您的... 省略号的至少一部分的情况下,我们无法冒险猜测...如果您跳过using 并尝试struct derived_temp&lt;key&gt;: base&lt;derived_temp&lt;key&gt;&gt; 会发生什么? base 的参数是什么?它继承自什么?
  • @Massa 我明白了,但是半小时后我仍然无法找出问题,所以我决定只添加 public 关键字而不是继续搜索 :-)
  • @Massa 如果跳过using,没有任何变化。 base 将单个参数传递给派生类,例如D,它继承自同样以D 为模板的实用程序类,该类提供重载方法der() 以方便地将对象转换为D&amp;&amp;、@987654338 @,或const D&amp;。就是这样。
  • 忘了问:哪个版本的clang?
  • @Massa clang 3.3。不幸的是,我还没有 3.4。

标签: c++ inheritance struct public


【解决方案1】:

代码:

struct T1 {
  int x;
};

struct T2 : T1 {
  int y;
};

int main( int argc, char * argv[] ) {
  T2 t2;
  t2.x = 3;

  return t2.x;
}

构建/运行:

~ clang blah.cc -o blah; ./blah; echo $?
3
~ clang blah.cc -std=c++11 -o blah; ./blah; echo $?
3

简而言之:默认为公共继承。


我花了更多时间来让它更接近 OPs 代码;这是我整理的(请原谅拼写错误;我正在使用气隙机器进行测试):

template <class T>
struct base {
  T x;
  template <typename I> I blah( I i ) const { return i + x.k.y; }
}

template <class T>
struct derived_temp;
struct key { int y; };
using derived = derived_temp<key>;
template <>
struct derived_temp<key> : base <derived> {
  int z;
  key k;
};

int main( int argc, char * argv[] ) {
  derived d;

  d.x   = 1;
  d.k.y = 2;
  d.z   = 3;

  return 0;
}

内置:

~ clang --version
clang version 3.4 (tags/RELEASE_34/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
~ clang++ test.cc -o test -std=c++11

我遇到两个基本错误(我没有引用完整的内容,因为我必须手动输入全部内容):

test.cc:3:5: error: field has incomplete type 'derived_temp<key>'
test.cc:21:5: error: no member named 'x' in 'derived_temp<key>'

当我盯着这个,试图了解您的动机/意图以及错误所说的内容时,我突然想到您正在尝试进行循环继承以在循环中定义事物甚至不可能的时尚。

【讨论】:

  • 澄清一下,当我使用 clang 3.2 和 3.3 构建时,我遇到了同样的错误。
  • 这是你自己定义base的方式的问题。 Tbase 的派生类型。所以你不能只在base 中拥有T 类型的成员。我当然不会那样做。我只使用Tstatic_cast base 对象,例如至T&amp;,如上面 cmets 中所述。
  • 看看你能不能做一个和我尝试的一样的玩具例子;假设您最终没有在此过程中解决它,请将其发布以供我们查看。否则,我们只能猜测诸如 base 源自什么、存在哪些成员、有多少模板参数等。
  • 我不小心取得了一些进展。 derived_temp 最初声明为 class,然后特化定义为 struct,派生 base。现在,如果我在声明中也使用struct,错误就会消失。这是一个非常干净的解决方法。不幸的是,这看起来仍然无效,我仍然无法在任何玩具示例中隔离它。它只发生在大型项目中。
【解决方案2】:

那里有点不对劲。默认情况下,结构应使用公共继承。暂时忘记模板和 using 指令。

使用最简单的代码进行测试,以设置您怀疑的失败案例:

struct Base
{
int i;
};

struct Derived : Base
{
};

现在尝试从 Derived 实例访问 i。如果可行,并且应该开始添加功能,直到它具有与原始代码相同的所有组件。

现在我自己还没有 clang 来测试它。所以我只是建议前进的方向。

【讨论】:

  • 这就是大型项目的问题:你不能只“添加功能,直到它具有与原始代码相同类型的组件”而不重写一半的项目。
  • 这在很大程度上取决于问题的类型。在这种情况下,似乎是语言或语言功能的使用导致了问题。因此,您可能不需要重写一半的项目,而只需要建模的关系类型。我怀疑复制案例很有可能只涉及 3 个对象。
  • 我可能会再试一次。现在我尝试了一个多小时没有成功,所以我提出了这个问题,以防万一我忽略了某些东西并应用了简单的解决方法。
猜你喜欢
  • 1970-01-01
  • 2011-01-05
  • 2011-03-11
  • 2011-08-10
  • 1970-01-01
  • 2019-08-24
  • 1970-01-01
相关资源
最近更新 更多