0

我正在尝试构建以下架构:

struct A{
   int x;
}
struct B: public A{
   int additinal_data;
}
struct ContainerA{
  std::vector<A> va; 
}
struct ContianerB{
  std::vector<B> vb;
  int additional_data;
}

我想以一种不仅可以为 ContainerA 类型而且还可以为 ContainerB 调用函数的方式重新组织以下代码。

double sum(ContainerA &ca) {
   double res = 0;
   for (const auto &a: ca.va) 
       res += a.x;
   return res;
}

如果能够将模拟函数作为 ContainerA 的成员移动,但也可以从 ContainerB 访问(即 ContainerA ca; ca.sum()),那也很好。就这样。我怎样才能重新设计我的架构以允许这样的调用?

4

4 回答 4

1

sum与 aContainerA或.一起使用的一种方法ContainerB

  1. 使函数成为函数模板。
  2. 更新ContainerAContainerB它们可以用于范围for循环和<algorithm>标准库头文件中的许多函数。
struct ContainerA
{
  std::vector<A> va; 

  // Add const and non-const versions of begin() and end().

  using iterator = std::vector<A>::iterator;
  using const_iterator = std::vector<A>::const_iterator;

  iterator begin() { return va.begin(); }
  iterator end() { return va.end(); }

  const_iterator begin() const { return va.begin(); }
  const_iterator end() const { return va.end(); }

};

struct ContianerB
{
  std::vector<B> vb;
  int additional_data;

  // Add const and non-const versions of begin() and end().

  using iterator = std::vector<B>::iterator;
  using const_iterator = std::vector<B>::const_iterator;

  iterator begin() { return vb.begin(); }
  iterator end() { return vb.end(); }

  const_iterator begin() const { return vb.begin(); }
  const_iterator end() const { return vb.end(); }

};

template <typename Container>
double sum(Container const& container)
{
   double res = 0;
   for (const auto &a: container) 
       res += a.x;
   return res;
}
于 2020-08-18T16:34:59.433 回答
1

我认为在Steve Jessop 的协方差示例中隐含显示的方法中,不可能将值static_cast派生引用引用到它的Base类型引用,因为那样你将创建一个“临时引用”,但我可能错了。因此,我创建了一个方法(称为),它返回一个可能强制转换的指针,该指针肯定存在。getIdentifergetElement

ContainerA因为你可能真的想要和之间有明确的关系ContainerB(在重复代码的情况下),我写了一个class基于 - 的例子来说明如何实现它。否则,使用模板函数可能是要走的路。

如果您使用的是结构,则不需要public,protectedprivate标签,也不需要变量的设置器,但您当然需要一些getIdentifier方法来访问B类型元素。

这是一个演示程序:

一个

#pragma once
#include <iostream>

class A
{
public:
    A(const int& data);

    friend std::ostream& operator<<(std::ostream& s, const A& a);
protected:
    virtual std::ostream& toStream(std::ostream& s) const;
private:
    int m_data;
};

A::A(const int& data)
    : m_data{ data }
{
}

std::ostream& A::toStream(std::ostream& s) const
{
    return s << m_data;
}

std::ostream& operator<<(std::ostream& s, const A& a)
{
    return a.toStream(s);
}

#pragma once
#include "A.h"

class B : public A
{
public:
    B(const int& data, const int& additionalData);
    void setAdditionalData(int additionalData);
protected:
    virtual std::ostream& toStream(std::ostream& s) const;
private:
    int m_additinalData;
};

B::B(const int& data, const int& additionalData)
    : A{ data },
    m_additinalData{ additionalData }
{
}

void B::setAdditionalData(int additionalData)
{
    m_additinalData = additionalData;
}

std::ostream& B::toStream(std::ostream& s) const
{
    A::toStream(s);
    return s << '\t' << m_additinalData;
}

集装箱A

#pragma once
#include "A.h"

#include <vector>

class ContainerA
{
public:
    void push(A* a);
    size_t getSize() const;
    virtual A* getElement(const int& index);
    virtual A* operator[](const int& index);
protected:
    std::vector<A*> m_As;
};

void ContainerA::push(A* a)
{
    m_As.push_back(a);
}

A* ContainerA::getElement(const int& index)
{
    return m_As[index];
}

A* ContainerA::operator[](const int& index)
{
    return m_As[index];
}

size_t ContainerA::getSize() const
{
    return m_As.size();
}

集装箱B

#pragma once
#include "ContainerA.h"
#include "B.h" // The compiler should be able to tell that B is a subclass of A

class ContainerB : public ContainerA
{
public:
    B* getElement(const int& index) override;
    B* operator[](const int& index) override;
private:
    int additional_data;
};

B* ContainerB::getElement(const int& index)
{
    return static_cast<B*>(m_As[index]);
}

B* ContainerB::operator[](const int& index)
{
    return static_cast<B*>(m_As[index]);
}

主文件

#include "ContainerB.h"

int main()
{
    B b1{ 4, -1 };
    B b2{ 5, -1 };
    B b3{ 6, -1 };

    ContainerB contB{};
    contB.push(&b1);
    contB.push(&b2);
    contB.push(&b3);

    B* b{ contB.getElement(0) };
    b->setAdditionalData(0);

    size_t size{ contB.getSize() };
    for (int i{ 0 }; i < size; ++i) {
        std::cout << *contB.getElement(i) << std::endl;
        std::cout << *contB[i] << std::endl;
    }
}

输出

4       0
4       0
5       -1
5       -1
6       -1
6       -1

现在您可以传递ContainerB给期望 a 的函数/方法,ContainerA而无需存储冗余数据。

于 2020-08-18T21:08:30.837 回答
1

如何表达ContainerB“延伸”ContainerA

目前没有。但是,您可以轻松更改:

struct ContainerA{
  std::vector<A> va; 
};
struct ContianerB{
  std::vector<B> va;
  int additional_data;
};

当名称匹配时,静态多态性效果最好。

接着

template <typename Container>
double sum(Container const& container) 
/* requires AVector<Container> */
{
   double res = 0;
   for (const auto &a: container.va) 
       res += a.x;
   return res;
}

使用 C++20 概念进行更好的验证

template<typename T> concept ARange = 
    std::range<T>
 && std::derived_from<T::value_type, A>;
于 2020-08-18T18:08:42.863 回答
0

考虑使用静态多态性(模板)。

(代码未测试)

auto const& inner_vector(ContainerA& ca){return ca.va;}
auto const& inner_vector(ContainerB& cb){return cb.vb;}

template<class TContainer>
double sum(TContainer &c){
   double res = 0;
   for (const auto &a: inner_vector(c)) 
       res += a.x;
   return res;
}
于 2020-08-18T16:43:06.137 回答