【问题标题】:how to implement casting to a private base class in C++如何在 C++ 中实现转换为私有基类
【发布时间】:2010-09-17 19:57:20
【问题描述】:

如何在 C++ 中实现转换为私有基类?我不想使用诸如添加朋友之类的技巧。定义公共铸造运算符不起作用。

编辑:

例如我有:

class A {
//base class
}

class AX : private A {
//a child
}

class AY : private A {
//another specialized child
}

class B {
//base class
void do (A a) {//do
    }
}

class BX : private B {
//a child
void do (AX a) {
     B::do( static_cast <A> (a) );
    }
}

class BY : private B {
//another specialized child
void do (AY a) {
    B::do( static_cast <A> (a) );
    }
}

EDIT2

我为什么要这样做?

假设我必须定义一些重量级的属性,并且可以是几种相似的类型(如 VelocityX VelocityY 等)。然后我希望能够拥有可以具有任何这些属性集的类。如果我想处理这些属性,很明显,我宁愿将它们转换为它们的基本类型,而不是为每个变体添加一个实现。我不使用公共继承,因为最好在需要的地方显式转换,而不是让私有接口隐式可见。不是一个真正的问题,但我想有一个解决方案:)

【问题讨论】:

  • 您能告诉我们您想做什么吗?这看起来像非常糟糕的设计。为什么不使用公共继承?还是组合和getter函数?您能否也提供给我们不起作用的代码?
  • 请注意,许多人并不认为 friend 是“黑客”。
  • 当您有很多课程可能需要添加到该朋友列表中时,我认为这是一种 hack
  • 你在上面的一些不错的切片......
  • private继承意思 “不要把它当作它的基础。”这具有非常强烈的代码气味。我建议您完全重新考虑您的方法。

标签: c++ casting base-class


【解决方案1】:

如果定义公共转换运算符不起作用,您可以尝试使用常规函数:

class D: private B {
    public:
        B& asB() { return static_cast<B&>(*this); }
};
...
D d;
d.asB().methodInB();
...

不管怎样,有什么意义呢?如果D 私下派生自B,那么您不应该从外部使用D 作为B

【讨论】:

  • +1 - 这将是我的评论,包括“有什么意义?”问题。
【解决方案2】:

您可以只使用 C 风格的演员表。不需要任何“黑客”或“实施”。将它包装成一个显式函数服务于“C 风格的演员是坏的”人

template<typename Targ, typename Src>
typename boost::enable_if<boost::is_base_of<Targ, Src>, Targ>::type &
private_cast(Src &src) { return (Targ&)src; }

为了确保演员表安全,您需要确保 Targ 实际上是一个私有或公共基础。这是由boost::is_base_of 完成的。


当然,您应该更喜欢各自派生类中返回基指针的成员函数,而不是进行这样的强制转换。


定义公共转换运算符不起作用。

这对我来说没有意义……那为什么还要将基类设为私有呢?就公开吧。您的转换函数不起作用的原因是因为标准要求隐式转换从不考虑将转换函数转换为基类、类本身或void

【讨论】:

  • C 风格转换的结果(在这种情况下相当于 reinterpret_cast)是实现定义的,不是吗?
  • @avakar 它不等同于 reinterpret_cast,而是禁用访问检查的 static_cast(参见 5.4/7)。
  • 我的天,这是真的!来自我的 +1。
  • “将其包装到显式函数中服务于“C 样式转换是坏”的人”:人们认为 C++ 中的 C 样式转换是错误的,这有什么问题吗?我的意思是:我的 C 风格转换隐藏了一些错误,这些错误会被 static_cast 捕获(从 Derived * 转换为 Base2 *,这些类型仅被前向声明)。我错过了什么吗?
  • @paercebal 他们和那些说蓝色是漂亮颜色的人一样错误和正确。写出你认为对你和你的同事来说最易读和维护的东西。在转换为私有基类的情况下,我也会将它包装到一个函数中,以作记录。但我不同意笼统且无上下文的“C++ 中的 C 风格转换是错误的”。
【解决方案3】:

我有一个用例;我继承自一个大型且易变的基类,该基类一直在添加函数,而基类函数几乎永远不会在我的子类中正常工作,所以我私下继承。

我认为创建一个返回基类的函数是最简单的。下面我列出了一个完全更正的程序;请在提交问题之前尝试编译您的代码,因为使用诸如“do”之类的标识符作为函数名称可能会使每个编译器都不满意.. :-( :-(

class A {
  //base class                                                                                                                                                          
};

class AX : private A {
  //a child                                                                                                                                                             
 public:
  A *ToA() { return this; }
};

class AY : private A {
  //another specialized child                                                                                                                                           
 public:
  A *ToA() { return this; }
};

class B {
  //base class                                                                                                                                                          
 protected:
  void do_it (A a) {};
};

class BX : private B {
  //a child                                                                                                                                                             
  void do_it (AX a) {
    B::do_it( *a.ToA() );
  }
};

class BY : private B {
  //another specialized child                                                                                                                                           
  void do_it (AX a) {
    B::do_it( *a.ToA() );
  }
};

【讨论】:

    猜你喜欢
    • 2014-09-25
    • 1970-01-01
    • 1970-01-01
    • 2020-01-10
    • 1970-01-01
    • 1970-01-01
    • 2017-09-24
    • 2013-07-29
    • 1970-01-01
    相关资源
    最近更新 更多