2013-11-25 20 views
0

我有一个类,并且有几种方法可以遍历它。例如,您可以迭代查看其中的所有ABC。该课程没有虚拟功能。通过将父类转换为子引用来提供类的迭代“视图”

我希望这些有一个很好的界面。我想知道下面是否给出了未定义或不明确的行为,或者是否可以做。

我想使这一类的三个子类:

// can look at this in three ways 
struct myClass { 
    void myFunc(); 
}; 

struct A_view : public myClass { 
    A_iterator begin(); 
}; 

struct B_view : public myClass { 
    B_iterator begin(); 
}; 


struct C_view : public myClass { 
    C_iterator begin(); 
}; 

然后

A_view& get_C_view(const myClass& c) { 
    return *reinterpret_cast<B_view*>(&c); 
} 

B_view& get_B_view(const myClass& c) { 
    return *reinterpret_cast<B_view*>(&c); 
} 

C_view& get_C_view(const myClass& c) { 
    return *static_cast<C_view*>(&c); 
} 

我希望能够做到这样使用它

myClass inst; 

for (auto& c : get_C_view(inst)) 
    //stuff 

for (auto& b : get_B_view(inst)) 
    //stuff 

auto& bview = get_b_view(inst); 

std::transform(bview.begin(), bview.end(), bview.begin(), [](auto& x, auto& y) { /* smthing */ }); 

bview.myFunc(); 

或任何与<algorithm>算法。如您所见,您还可以使用视图上父类中定义的函数。

所以,我将一个实例强制转换为从其派生的类型的引用,该类型仅添加函数,而不是数据,但实际上并不是这些类型之一。

可以吗? “OK”我的意思是

  1. 这是明确的,未定义的或未指定的行为?
  2. 如果没有明确定义,这是否会导致实践中的问题?
  3. 药草萨特会皱眉吗?
+0

为什么不只有'A_begin','A_end'等方法?或者,如果您为每种类型设置单独的类,请将“A_view”设置为朋友类,而不是派生类。 –

+0

@TaylorBrandstetter因为我的实际情况太多了。而且那些不能用于需要'begin' /'end'方法的东西,比如基于范围的。 – Jay

+0

如果您只是简单地将'A_view'作为独立类而不是派生类(如下面的答案),那么您应该能够以完全相同的方式使用它,并且编写几乎相同数量的代码行。如果“c_begin()”的等价物是私有的,你只需要把它变成朋友。 –

回答

3

继承是不是在这种情况下,出于多种原因,使用正确的工具,第一个是,你可以不投对象的类型,这是没有,但更普遍比因为继承是第二高的耦合在语言中的关系,应该谨慎使用(即在需要时,而不仅仅是因为)。

可以创建用于保存关于你型薄膜包装类型和它们的开始/结束的功能映射到在你的组件的相应的观点:

struct C_view { 
    MyClass &obj; 
    C_view(MyClass& obj) : obj(obj) {} 
    C_iterator begin() { 
    return obj.c_begin(); 
    } 
    C_iterator end() { 
    return obj.c_end(); 
    } 
}; 

然后用户代码变为:

for (auto &c : C_view(inst)) { 
    ... 
} 
+0

但是,然后你必须有一个更加笨拙的方式来访问被包装的东西上的函数。所以,在你的回答开始时,这是不确定的还是未说明的或......? – Jay

+1

@Jay:所以你宁愿有未定义的行为,而不是输入更多?这是一种选择,但你的同事可能不同意你的方法。 –

+0

你从未说过它是未定义的,那是我的问题。 – Jay