我可以将成员数据指针分配给派生类型吗?
这可能最好用示例代码来展示。以下内容无法使用 g++ 进行编译:
struct Base {
};
struct Derived : public Base {
};
struct Container {
Derived data_;
};
int main(void) {
Base Container::*ptr = &Container::data_;
}
我收到以下错误:从“Derived Container::*”到 Base Container::*' 的转换无效
。 这是语言不允许的吗?这是编译器错误吗?我使用了错误的语法吗?
请帮忙!
关于我为什么要这样做的一些背景:我有几个成员数据块,我想主要将它们用作它们的派生类型,但我希望能够通过一些通用代码来填充它们。数据将以任意顺序出现,并具有一个字符串标签,我将使用它来选择要填充的适当成员数据。我计划创建一个 std::map
通过通用接口将数据分配给每个成员。我想避免使用巨大的 if else
构造来查找正确的成员数据。
This is probably best shown with example code. The following fails to compile with g++:
struct Base {
};
struct Derived : public Base {
};
struct Container {
Derived data_;
};
int main(void) {
Base Container::*ptr = &Container::data_;
}
I get the following error: invalid conversion from 'Derived Container::*' to Base Container::*'
.
Is this not allowed by the language? Is this a compiler bug? Am I using the wrong syntax?
Please help!
Some background as to why I'm trying to do this: I have several member data pieces that I want to use primarily as their derived types, but I want to be able to populate them through some common code. Data will be coming in an arbitrary order and have a string label that I would use to select the appropriate member data to populate. I was planning on creating a std::map<std::string, Base Container::*>
to assign data to each member through a common interface. I'd like to avoid have a giant if else
construct to find the right member data.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
这不是编译器错误,你不能这样做。 (但是您可以将 Base::* 分配给 Derived::*)。
我没有看到任何限制的充分理由(除了处理多重继承的情况,这会使成员指针的表示更加复杂)。
This is not a compiler bug, you can't do that. (But you can assign a Base::* to a Derived::*).
I don't see any good reason for the limitation (excepted that to handle the case of multiple inheritance, that would complicate even more the representation of a member pointer).
这篇文章中有很多相当复杂的、一些解释不清的答案,以及一些完全错误的答案。
但在我看来,问题在于
Container
中根本没有Base
成员——只有一个Derived
成员。你不能这样做:...出于同样的原因,你不能这样做:
在第二个示例中,对象不是
long
,它是int
。同样,在第一个示例中,对象不是Base
,而是Derived
。作为一个可能的切线点,在我看来,您真正想做的是让
Base
成为一个抽象类,并让Container
有一个Base*< /code> 而不是
Derived
成员。There are a lot of fairly complex, some not-well-explained, and a few flat wrong answers in this thread.
But the problem, it seems to me, is that there simply isn't a
Base
member withinContainer
-- there is aDerived
member. You can't do this:...for the same reason you can't do this:
In the second example, the object isn't a
long
, it's anint
. Similarly, in the first example the object isn't aBase
, it's aDerived
.As a possibly tangential point, it seems to me like what you really want to do is have
Base
be an abstract class, and haveContainer
have aBase*
rather than aDerived
member.C++ 中指向成员的指针实际上并不是指针,而更像是给定成员的偏移量,并且特定于类型,因此您尝试执行的操作并未得到真正支持。
这里有一个关于 Stackoverflow C++:指向类数据成员的指针的不错的讨论。
Pointers to members in C++ are not really pointers but more like offsets to given member and are specific to the type, so what you are trying to do is not really supported.
Here's a decent discussion here on Stackoverflow C++: Pointer to class data member.
您只需要编写:
但
container
必须是Container
的实例,因此您必须在某处创建该类型的一个变量。You just need to write:
but
container
has to be an instance ofContainer
, so you have to create one variable of that type somewhere.即使 A 和 B 之间可以进行转换,您也无法将 C::*A 转换为 C::*B。
但是,您可以执行
You cannot convert C::*A to C::*B even if there is a conversion possible between A and B.
However, you can do this:
您必须使用
static_cast
来执行此转换,如 5.3.9/9 中所示。这样做的原因是它充当从父对象指针到子对象指针的static_cast
。换句话说,将指向派生成员的指针放入指向父成员的指针中将允许您从父对象或指针访问不存在的派生成员。如果标准自动允许这样做,那么很容易搞砸并尝试访问不属于适当子类型(包含所述成员)的类上的子成员。如果没有更多信息,听起来您需要在
Base
类中使用不同/更好的构造函数/设置接口,而不是尝试在此处使用指向成员的指针。You would have to
static_cast
to do this conversion as seen in 5.3.9/9. This reason for this is that it acts as astatic_cast
from parent object pointer to child object pointer would. In other words, putting a pointer to a derived member into a pointer-to-parent-member would allow you to possibly access a non-existent derived member from a parent object or pointer. If the standard allowed this automatically it would be easy to mess up and try to access a child member on a class that isn't of the appropriate child type (that contains said member).Without more information it sounds like you need a different/better constructor/set interface in your
Base
class rather than trying to use pointers-to-member here.我认为你想要的是一个“容器”,即一个只有指针的结构:
现在你知道的每个成员都属于特定类型(即 DerivedA、DerivedB 等),这样你就可以稍后对它们进行向下转换。
但首先您正在接收数据(以任意顺序),但带有字符串名称,因此您应该有一个地图:
并且您必须已经填充了地图:
现在数据到达并且您开始填充容器:
myMap[key ]
选择容器的正确成员,并且factory(key,data)
创建实例。顺便说一句,无论如何,您都可以将地图作为容器:
std::map
I think what you want is a 'container', ie a struct which just has pointers:
Now each of the members you know to be of a specific type (ie DerivedA, DerivedB etc) so you can down-cast them later.
But first you are receiving data (in arbitrary order), but with a string name, so you should have a map:
And you must have already populated the map:
Now data arrives and you start populating the container:
myMap[key]
picks the right member of the container andfactory(key,data)
creates instances.btw you could just have a map as your container anyway:
std::map<std::string, Base*>
关于最初的问题,您可以使用指向函数的指针来完成此操作,而不是引入基类。
那么如何实现
set
呢?Regarding the original issue, you can do this using pointer to functions, instead of introducing base classes.
How to implement
set
then ?第一个问题是
Container
没有一个名为ptr
的成员可以工作。请注意,需要有一个容器对象来创建 data_ 成员,并且需要将其公开。
另一种方法是让 returned::data_ 成为静态成员。
The first problem is that
Container
doesn't have a member calledptr
Would work. Note that there needs to be a container object to create the data_ member and it would need to be made public.
The alternative would be for derived::data_ to be a static member.