问题描述
我正在尝试构建以下架构:
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()),这也很好。 但是,ContinerB与ContainerA不协变,因此我很难做到这一点。我该如何重整架构以允许进行此类调用?
解决方法
将sum
与ContainerA
或ContainerB
一起使用的一种方法。
- 使功能成为功能模板。
- 更新
ContainerA
和ContainerB
,使其可以在range-for
循环以及标准库的<algorithm>
标头中的许多函数中使用。 li>
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;
}
,
如何表达
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>;
,
我认为不可能通过pathname: this.props.history.location.pathname
方法将值的派生引用到它的 Base 类型引用中,如隐式所示 Steve Jessop's covariance example ,因为那样您会创建一个“临时参考”,但是我可能是错的。因此,我改为使用一种方法(称为static_cast
)返回可能强制转换的指针,该指针肯定会存在。
因为您可能真的想在getIdentifer
和getElement
之间有明确的关系(如果代码重复),所以我写了一个基于ContainerA
的示例,说明了如何实现它。否则,使用模板函数可能是可行的方法。
如果您使用的是结构,则不需要ContainerB
,class
和public
标签,也不需要变量的setter,但是您当然需要em>需要某种protected
方法来访问private
类型的元素。
这是一个演示程序:
A
getIdentifier
B
B
容器A
#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);
}
容器B
#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;
}
main.cpp
#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();
}
输出
#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
的函数/方法,而不必存储冗余数据。
考虑使用静态多态性(模板)。
(代码未经测试)
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;
}