gpt4 book ai didi

c++ - 在继承中更改成员类型

转载 作者:太空狗 更新时间:2023-10-29 20:12:43 25 4
gpt4 key购买 nike

给定一个基类 Base,它有两个派生类 DerADerB,派生类是否可以有一个成员变量用于在 Base 成员函数中,但每个类的类型不同吗?

class Base {
* a // Declare a as *something*, so it can be used by "doWork"

template <typedef T>
void doWork(T b) { // Add another value to "a" which is of its same type
a += b; // For example; an operation that works on "a", no matter what numeric type it is
}
}

class DerA : public Base {
// Make "a" an int
}

class DerB : public Base {
// Make "a" a float
}

在实践中,a 将是一个基本结构,而 DerADerB 将具有基本结构的派生版本(派生类将每个都有一个特定于其用途的结构派生形式,但每个都必须对 a 执行简单操作,因此当我只能使用 a 时,为每个派生复制/粘贴该简单函数似乎毫无意义模板函数)。我只会键入 a 作为基本结构类型,但随后我无法访问每个派生结构具有的各种专用成员函数和变量(如果我正确理解继承的话)。

如果这个问题是重复的,我很抱歉,但我不知道这种品质会被称为什么,所以谷歌搜索没有结果。

最佳答案

您可能需要的是 CRTP .

template<class D>
struct Base {
D* self() { return static_cast<D*>(this); }
D const* self() const { return static_cast<D*>(this); }
template<class T>
void doWork(T b) {
self()->a += b;
}
};
struct DerA : public Base<DerA> {
int a;
};
struct DerB : public Base<DerB> {
double a;
};

这里我们将派生类型传递给我们的基类。在基类中,您可以使用 self()-> 访问派生类型中的字段。这允许基本上完全访问派生类型,同时让我们在基类中共享代码。

请注意,您不能通过这种方式将 DerADerB 作为 Base 传递。如果你想要那样,你需要一个virtual方法doWork,而virtualtemplate方法不存在。

CRTP代表奇怪的重复模板模式,我想这个名字是因为它很奇怪,它涉及重复一个类型,并且它不断出现在奇怪的角落是有用的。


类型删除可能也不起作用,因为您希望从代码库中的两个不同位置分派(dispatch)类型删除(双重分派(dispatch)问题:您需要支持类型的集中列表来执行笛卡尔积类型) .

要对此进行扩展,为了支持 a+=b 其中 ab 都是任意类型,您必须扩展遍历所有类型两次,包括在编译单元中的同一位置永远不会相互可见的类型。这是不可能的。


如果您需要一个公共(public)基础,并且只有一些类型可以传递给doWork,那么您可以这样做:

struct Base {
virtual void doWork( double ) = 0;
virtual void doWork( int ) = 0;
virtual void doWork( long long ) = 0;
};

template<class D>
struct Base_helper:Base {
D* self() { return static_cast<D*>(this); }
D const* self() const { return static_cast<D*>(this); }
template<class T>
void doWork_impl(T b) {
self()->a += b;
}
void doWork( double x ) override { doWork_impl(x); };
void doWork( int x ) override { doWork_impl(x); };
void doWork( long long x ) override { doWork_impl(x); };
};
struct DerA : public Base_helper<DerA> {
int a;
};
struct DerB : public Base_helper<DerB> {
double a;
};

请注意,doWork 的每个版本都必须有效才能调用每个 Der,因为 Base_helper 会实例化所有这些。

如果传递给 doWork 的类型是无界的,而 Der 的类型是有界的,那么您只能反向执行上述操作。然而,它变得尴尬。在这种情况下,您最好的选择是使用 boost::variant 类型的解决方案。

关于c++ - 在继承中更改成员类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26001987/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com