基类使用派生类的数据

时间:2015-03-16 20:51:13

标签: c++ inheritance

我有一个班级

Class A
{
    uint8_t* queue;
    uint32_t num_elems_queue;
    void DoSomethingWithQueue();
};

这个类将是我的库,将由不同的客户使用。 在使用上述类的客户端代码中,我将使用类似的东西。

Class B
{
    const uint32_t num_elems = 8;
    uint8_t queue[num_elems];
};

现在为了初始化A类中的数据,我有两个选择。一个是我在构造函数中将数据传递给类A,例如

Class A
{
    A(uint8_t* queue__, uint32_t num_elems_queue__): queue(queue__),num_elems_queue(num_elems_queue__)
    {
    }
    uint8_t* queue;
    uint32_t num_elems_queue;
    void DoSomethingWithQueue();
};

另一个是我从类A继承类B并在类A中具有返回指向所需数据的指针的纯虚函数。比如

Class A
{

    uint8_t* queue;
    uint32_t num_elems_queue;
    void DoSomethingWithQueue();
    virtual uint32_t get_num_elems_queue() = 0;
    virtual uint8_t* get_queue() = 0;
};

Class B : public A
{
    const uint32_t num_elems = 8;
    uint8_t queue[num_elems];
    uint32_t get_num_elems_queue()
    {
        return num_elems;
    }
    uint8_t* get_queue() 
    {
        return queue
    }
};

现在我的问题是哪种方式首选。我被告知第二种方法更好,但我的意见是,在第二种方法的情况下,我继承不扩展基类,而是将数据发送回基类。这是否违背了为什么要使用继承“扩展类的功能”的基本原因。

EDITED: 我认为这种情况可以通过将“num_elems”传递给A类来解决。但是通常当我们有一个处理不同数据的类时,最好继承并使用派生类中的数据。如果我错了,请纠正我。经过一番搜索,我在MSDN网站上找到了一个类似的例子: 代码在VB中我不是VB开发人员,但从我理解的场景是相同的。 来自https://msdn.microsoft.com/en-us/library/27db6csx%28v=vs.90%29.aspx

  

例如,假设您有一个管理多种内存列表的大型业务应用程序。一个是客户数据库的内存副本,在会话开始时从数据库读入以获取速度。数据结构可能如下所示:

Class CustomerInfo
    Protected PreviousCustomer As CustomerInfo
    Protected NextCustomer As CustomerInfo
    Public ID As Integer 
    Public FullName As String 

    Public Sub InsertCustomer(ByVal FullName As String)
        ' Insert code to add a CustomerInfo item to the list. 
    End Sub 

    Public Sub DeleteCustomer()
        ' Insert code to remove a CustomerInfo item from the list. 
    End Sub 

    Public Function GetNextCustomer() As CustomerInfo
        ' Insert code to get the next CustomerInfo item from the list. 
        Return NextCustomer
    End Function 

    Public Function GetPrevCustomer() As CustomerInfo
        'Insert code to get the previous CustomerInfo item from the list. 
        Return PreviousCustomer
    End Function 
End Class
  

您的应用程序可能还有一个类似的用户已添加到购物车列表的产品列表,如以下代码片段所示:

Class ShoppingCartItem
    Protected PreviousItem As ShoppingCartItem
    Protected NextItem As ShoppingCartItem
    Public ProductCode As Integer 
    Public Function GetNextItem() As ShoppingCartItem
        ' Insert code to get the next ShoppingCartItem from the list. 
        Return NextItem
    End Function 
End Class
  

您可以在此处看到一种模式:两个列表的行为方式相同(插入,删除和检索),但对不同的数据类型进行操作。保持两个代码库以执行基本相同的功能是无效的。最有效的解决方案是将列表管理分解为自己的类,然后从该类继承不同的数据类型:

Class ListItem
    Protected PreviousItem As ListItem
    Protected NextItem As ListItem
    Public Function GetNextItem() As ListItem
        ' Insert code to get the next item in the list. 
        Return NextItem
    End Function 
    Public Sub InsertNextItem()
        ' Insert code to add a item to the list. 
    End Sub 

    Public Sub DeleteNextItem()
        ' Insert code to remove a item from the list. 
    End Sub 

    Public Function GetPrevItem() As ListItem
        'Insert code to get the previous item from the list. 
        Return PreviousItem
    End Function 
End Class
  

ListItem类只需要调试一次。然后,您可以构建使用它的类,而无需再次考虑列表管理。例如:

Class CustomerInfo
    Inherits ListItem
    Public ID As Integer 
    Public FullName As String 
End Class 
Class ShoppingCartItem
    Inherits ListItem
    Public ProductCode As Integer 
End Class

2 个答案:

答案 0 :(得分:0)

B

获取课程A通常是优越的选择

例如:

class Vehicle
{
public:
    int WheelCount;
};

class Truck : public Vehicle
{
public:
    int LadderHeight;
};

Truck也是Vehicle。因此,您使用派生。属性WheelCount也将在Truck中提供。

一般来说,推导意味着 是另一回事。在这个例子中,卡车是一辆车。你也可以说MonsterTruck是卡车(即多重推导)。

尽管您可以使用std::vectorstd::list,但我不认为这是问题所在。我只是觉得值得一提......

答案 1 :(得分:0)

  

现在我的问题是首选方式。

答案将受到意见和其他因素的严重影响,例如其他程序的编码风格或您正在解决的具体问题的详细信息。

所以,只需做一些有效的事情并通过代码审查,然后注意它在项目生命周期中的运作情况。然后,下次你必须做出类似的设计决定时,你可以根据经验并充分了解具体项目来做出决定。


  

最有效的解决方案是将列表管理分解为自己的类,然后从该类继承不同的数据类型:

该陈述过于宽泛,特别是C ++有比VB更多的设计工具。考虑到C ++也有一个通用的list类型,使用它根本不涉及继承。


还有其他一些实施方案。

  1. 您的班级A目前对数据成员和DoSomethingWithQueue()成员函数使用实现继承。您可以通过消除数据成员来减少实现继承。

    class A
    {
      // A has no data members
    public:
      void DoSomethingWithQueue(); // implemented purely in terms of the virtual functions
    protected:
      virtual uint32_t get_num_elems_queue() = 0;
      virtual uint8_t* get_queue() = 0;
    };
    
  2. 您还可以完全避免继承:

    template<typename QueueContainer>
    void DoSomethingWithQueue(QueueContainer const &qc);
    
    class B {
    public:
      uint32_t get_num_elems_queue();
      uint8_t* get_queue();
    };
    
    B b;
    DoSomethingWithQueue(b);
    

    以上假设与您指定的B具有相同的基本界面,但也可以有更好的设计。例如,您可能希望它符合标准Container概念,而不是拥有自定义get_queue()get_num_elements_queue()成员。然后,您甚至可以使用标准Container而不是定义自己的class B