为了这个问题,这被大大简化了.说我有一个层次结构:
struct Base {
virtual int precision() const = 0;
};
template<int Precision>
struct Derived : public Base {
typedef Traits<Precision>::Type Type;
Derived(Type data) : value(data) {}
virtual int precision() const { return Precision; }
Type value;
};
Run Code Online (Sandbox Code Playgroud)
我想要一个带有签名的非模板函数:
Base* function(const Base& a, const Base& b);
Run Code Online (Sandbox Code Playgroud)
函数结果的具体类型与任何一个类型相同a且b具有更大的类型Precision; 像下面的伪代码:
Base* function(const Base& a, const Base& b) {
if (a.precision() > b.precision())
return new A( ((A&)a).value + A(b.value).value );
else if (a.precision() < b.precision()) …Run Code Online (Sandbox Code Playgroud) (这个问题应该通过对Stroustrup的引用来回答.)
能够请求指向最派生类的指针似乎非常有用,如下所示:
class Base { ... };
class DerivedA { ... };
class DerivedB { ... };
class Processor
{
public:
void Do(Base* b) {...}
void Do(DerivedA* d) {...}
void Do(DerivedB* d) {...}
};
list<Base*> things;
Processor p;
for(list<Base*>::iterator i=things.begin(), e=things.end(); i!=e; ++i)
{
p.Do(CAST_TO_MOST_DERIVED_CLASS(*i));
}
Run Code Online (Sandbox Code Playgroud)
但是c ++中没有提供这种机制.为什么?
更新,激励示例:
假设您没有Base和Derived and Processor,而是拥有:
class Fruit
class Apple : public Fruit
class Orange: public Fruit
class Eater
{
void Eat(Fruit* f) { ... }
void Eat(Apple* f) { Wash(f); ... }
void …Run Code Online (Sandbox Code Playgroud) 如果虚拟函数表对于类的所有对象都是相同的,那么为什么指向该表的指针(vfptr)不能是静态的并且在所有对象之间共享?
正如"四人帮"在" 设计模式 "中所述:" 人们经常说 '继承打破了封装'",在"面向对象编程语言中的封装和继承"中解释Snyder.
然而,每次我读" 继承断裂包封 ",这要求背后的原因要么依稀解释的,或与所述的一个例子说明脆基类的问题.
在阅读论文时,我感觉真正打破封装的唯一继承属性是downcalls,这是开放递归(动态调度打开this)允许的特性,并定义为"当超类方法调用在子类中重写的方法时",根据Ruby&Leavens在"安全地创建正确的子类而不看超类代码"中的说法.
此外,根据Aldrich在"选择性开放递归:脆弱基类问题的解决方案"中的说法,开放递归显然是导致脆弱基类问题的原因.
因此,如果脆弱基类问题是"继承打破封装"的唯一原因,那么可以更清楚地说,下调会破坏封装.由于存在一些解决方案以避免在使用继承时进行下调,因此继承本身并不真正涉及破坏封装.此外,四人帮提出的取消继承的委托模式也可以允许开放递归和下调,因为委托人的context(this)由委托使用(这可能导致一种脆弱的委托类问题).
因此,我的问题是:
脆弱的基类问题是否被称为"继承打破封装"的唯一原因?
我最初在尝试创建一个 Rayon ParallelIterator 时遇到了这个问题,该flat_map操作被应用于动态次数,请参阅 Rayon 问题跟踪器上的这篇文章。
注意:我也在 Rust 用户论坛上问过同样的问题(请参阅此处),但 StackOverflow 可能是解决此问题的更好场所。
对于标准(即串行执行)Iterators 以下工作:
fn fancy<Input, Output, Item>(input: Input, depth: usize) -> Output
where
Input : IntoIterator<Item = Item>,
Output : std::iter::FromIterator<Item>,
Item : Copy + std::ops::Add<Output = Item>,
{
let mut iter: Box<dyn Iterator<Item = Item>> = Box::new(input.into_iter());
for _ in 0..depth {
iter = Box::new(iter.flat_map(|x| vec![x, x + x].into_iter()));
}
iter.collect()
}
Run Code Online (Sandbox Code Playgroud)
ParallelIterator然而,当使用 Rayon 的s 时,事情变得不确定:ParallelIterator需要实现它的类型是Sized,使它们非对象安全,因此不可能作为特征对象传递。因此,以下直接翻译不起作用: …
First if all, of the polymorphism answers I find, it's always like "if the base function is not virtual and the derived object is stored in a pointer of type base, then you cannot call the derived function". But they never tell you what to do when you want to do exactly that. And that's what I need to do.
I have a base class B that I have no control over. It's open source (TwoWire from Arduino library) …
在Smalltalk中,在运行时查找的方法可能涉及大量的步骤,因为一个子类的方法字典中不包含它的超类的方法,和一个指针追逐,需要找对方法.优化将是每个子类在其方法字典中存储所有超类方法.
问题:如何做到这一点?
一个明显的缺点是空间成本,但我只是想知道如何在Smalltalk中完成这项工作?这与为最近调用的方法创建单独的缓存不同.
最近我一直在学习高级 Rust。作为其中的一部分,我正在学习使用动态调度。
在我的修补过程中,我遇到了一些问题。由于某种原因,我似乎无法访问已使用框和动态调度分配给变量的结构字段。例如,
fn main() {
let z: Box<dyn S>;
z = Box::new(A::new());
println!("{}", z.val);
}
trait S {
fn new () -> Self where Self: Sized;
}
struct A {
val: i32,
}
impl S for A {
fn new () -> A {
A {val: 1}
}
}
struct B {
val: i32
}
impl S for B {
fn new() -> B {
B {val:2}
}
}
Run Code Online (Sandbox Code Playgroud)
产生错误消息“错误[E0609]:val类型上没有字段Box<dyn S>”
有什么方法可以访问这些字段,还是我需要拼凑一个解决方法?
虽然 C++ 标准将虚拟调度的实现留给了编译器,但目前只有 3 个主要编译器(gcc、clang 和 msvc)。
当您通过指向抽象基类的指针调用抽象基类上的方法时,它们如何实现虚拟调度?构建期间如何设置 vtable?
一个简单的“好像”示例会很有用。
c++ polymorphism language-implementation vtable dynamic-dispatch
我有一组结构 、A、B、C和D,它们都实现了一个 Trait\n Runnable。
trait Runnable {\n fn run(&mut self);\n}\nimpl Runnable for A {...}\nimpl Runnable for B {...}\nimpl Runnable for C {...}\nimpl Runnable for D {...}\nRun Code Online (Sandbox Code Playgroud)\n我还有一个结构体,用作构造、\n 、和实例Config的规范。ABCD
struct Config {\n filename: String,\n other_stuff: u8,\n}\n\nimpl From<Config> for A {...}\nimpl From<Config> for B {...}\nimpl From<Config> for C {...}\nimpl From<Config> for D {...}\nRun Code Online (Sandbox Code Playgroud)\n在我的程序中,我想解析一个Config实例并根据字段的值构造A,\n B, C …
dynamic-dispatch ×10
c++ ×5
polymorphism ×3
rust ×3
inheritance ×2
rtti ×2
arduino ×1
iterator ×1
late-binding ×1
oop ×1
smalltalk ×1
string ×1
traits ×1
type-erasure ×1
vtable ×1