C++ “提供可编辑的”;“意见”;通过将父类强制转换为对子类的引用

C++ “提供可编辑的”;“意见”;通过将父类强制转换为对子类的引用,c++,C++,我有一个类,有几种方法可以迭代它。例如,您可以迭代查看其中的所有A、B、或C。该类没有虚拟函数 我希望这些有一个很好的界面。我想知道下面是否给出了未定义或未指定的行为,或者是否可以这样做 我正在考虑制作这个类的三个派生类: // can look at this in three ways struct myClass { void myFunc(); }; struct A_view : public myClass { A_iterator begin(); }; str

我有一个类,有几种方法可以迭代它。例如,您可以迭代查看其中的所有
A
B
、或
C
。该类没有虚拟函数

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

我正在考虑制作这个类的三个派生类:

// 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();
};
然后

或者使用
中的算法。如您所见,您还可以在视图上使用父类中定义的函数

因此,我将一个实例强制转换为对一个类型的引用,该类型是从它派生的,它只添加函数,不添加数据,但实际上它不是这些类型中的一种

这样行吗?我的意思是“好”

  • 这是定义良好、未定义还是未指定的行为
  • 如果没有很好的定义,这在实践中会导致问题吗
  • 赫伯·萨特会对此皱眉吗

  • 在这种情况下,继承不是正确的工具,原因有多种,首先是您不能将对象强制转换为它不是的类型,但更普遍的是,因为继承是语言中第二高的耦合关系,应该谨慎使用(即在需要时,而不仅仅是因为)

    您可以创建包含对您的类型的引用的精简包装类型,并将其开始/结束函数映射到组件上的适当视图:

    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)) {
       ...
    }
    

    在这种情况下,继承不是正确的工具,原因有多种,首先是您不能将对象强制转换为它不是的类型,但更普遍的是,因为继承是语言中第二高的耦合关系,应该谨慎使用(即在需要时,而不仅仅是因为)

    您可以创建包含对您的类型的引用的精简包装类型,并将其开始/结束函数映射到组件上的适当视图:

    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)) {
       ...
    }
    

    在这种情况下,继承不是正确的工具,原因有多种,首先是您不能将对象强制转换为它不是的类型,但更普遍的是,因为继承是语言中第二高的耦合关系,应该谨慎使用(即在需要时,而不仅仅是因为)

    您可以创建包含对您的类型的引用的精简包装类型,并将其开始/结束函数映射到组件上的适当视图:

    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)) {
       ...
    }
    

    在这种情况下,继承不是正确的工具,原因有多种,首先是您不能将对象强制转换为它不是的类型,但更普遍的是,因为继承是语言中第二高的耦合关系,应该谨慎使用(即在需要时,而不仅仅是因为)

    您可以创建包含对您的类型的引用的精简包装类型,并将其开始/结束函数映射到组件上的适当视图:

    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)) {
       ...
    }
    

    为什么不使用
    A_开始
    A_结束
    等方法呢?或者,如果设置为每种类型都有单独的类,请将
    A_视图
    设置为友元类,而不是派生类。@TaylorBrandstetter,因为在我的实际情况中有太多的类。同样,那些不适用于需要
    begin
    /
    end
    方法的东西,比如基于范围的for。如果您只是将
    A_视图
    作为一个独立类而不是派生类(如下面的答案所示),您应该能够以完全相同的方式使用它,并编写几乎相同数量的代码行。如果等价的
    c\u begin()
    是私有的,你只需要把它变成朋友。为什么不干脆用
    a\u begin
    a\u end
    等方法呢?或者,如果设置为每种类型都有单独的类,请将
    A_视图
    设置为友元类,而不是派生类。@TaylorBrandstetter,因为在我的实际情况中有太多的类。同样,那些不适用于需要
    begin
    /
    end
    方法的东西,比如基于范围的for。如果您只是将
    A_视图
    作为一个独立类而不是派生类(如下面的答案所示),您应该能够以完全相同的方式使用它,并编写几乎相同数量的代码行。如果等价的
    c\u begin()
    是私有的,你只需要把它变成朋友。为什么不干脆用
    a\u begin
    a\u end
    等方法呢?或者,如果设置为每种类型都有单独的类,请将
    A_视图
    设置为友元类,而不是派生类。@TaylorBrandstetter,因为在我的实际情况中有太多的类。同样,那些不适用于需要
    begin
    /
    end
    方法的东西,比如基于范围的for。如果您只是将
    A_视图
    作为一个独立类而不是派生类(如下面的答案所示),您应该能够以完全相同的方式使用它,并编写几乎相同数量的代码行。如果等价的
    c\u begin()
    是私有的,你只需要把它变成朋友。为什么不干脆用
    a\u begin
    a\u end
    等方法呢?或者,如果设置为每种类型都有单独的类,请将
    A_视图
    设置为友元类,而不是派生类。@TaylorBrandstetter,因为在我的实际情况中有太多的类。同样,那些不适用于需要
    begin
    /
    end
    方法的东西,比如基于范围的for。如果您只是将
    A_视图
    作为一个独立类而不是派生类(如下面的答案所示),您应该能够以完全相同的方式使用它,并编写几乎相同数量的代码行。如果等价的
    c_begin()
    是私有的,你只需要把它当作朋友。但是,你必须有一种更笨拙的方式来访问被包装的东西上的函数。那么