功能指针指向孩子与父母

发布于 2025-02-06 17:55:26 字数 652 浏览 2 评论 0原文

我正在学习C ++,并且我不断遇到一个奇怪的汇编错误。我将代码简化为以下示例:

#include <iostream>

class A {
public:
    static A foo()
    {
        A a;
        return a;
    }
};

class B : A
{
public:
    static B boo()
    {
        B b;
        return b;
    }
};

typedef A (*function)(void);

int main() {
    function f1 = A::foo;
    function f2 = B::boo; //error
    return 0;
}

我收到以下错误:

无法用类型为'b()'的lvalue初始化类型'函数'的变量(aka'a(*)()):不同的返回类型('a'vs'vs'b')

任何人都可以解释为什么它不起作用吗?由于ba的孩子, b 是a,为什么功能指针从“ void到<”代码> b “不像从“ void到a”的功能指针?

I'm learning C++ and I keep getting a weird compilation error I don't understand. I simplified my code to the following example:

#include <iostream>

class A {
public:
    static A foo()
    {
        A a;
        return a;
    }
};

class B : A
{
public:
    static B boo()
    {
        B b;
        return b;
    }
};

typedef A (*function)(void);

int main() {
    function f1 = A::foo;
    function f2 = B::boo; //error
    return 0;
}

I get the following error:

Cannot initialize a variable of type 'function' (aka 'A (*)()') with an lvalue of type 'B ()': different return type ('A' vs 'B')

Would anyone be able to explain why it doesn't work? Since B is a child of A, B is A, why is a function pointer from "void to B" isn't like a function pointer from "void to A"?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

内心激荡 2025-02-13 17:55:26

的确,C ++允许指向子类的指针将其转换为指针转换为父类(以某些条件为准)。

确实,C ++允许对子类的引用转换为对父类的引用(也要遵守某些条件)。

但是,这并不意味着C ++允许指向返回父类的函数,将父类转换为指针转换为返回子类的函数。这就是所显示的代码正在尝试执行的操作,这是不允许的。

那回答了您的“为什么”问题:因为在C ++中不允许这样做。至于原因,“为什么”;这主要是由于一些实际的考虑因素,但这并不重要,而C ++的规则不允许。

It is true that C++ allows a pointer to a child class to get converted to a pointer to the parent class (subject to certain conditions).

It is also true that C++ allows a reference to a child class to get converted to a reference to the parent class (also subject to certain conditions).

However, that does not mean that C++ allows a pointer to a function that returns a parent class to be converted to a pointer to a function that returns the child class. This is what the shown code is trying to do, and that is not allowed.

That answer your question of "why": because this is not allowed in C++. As far as why, the "why"; that's mostly due to some practical considerations, but that's immaterial, that's just not allowed by the rules of C++.

蓬勃野心 2025-02-13 17:55:26

您的函数声明它应该返回aboo返回a b,所以:

typedef A (*A_function)();
typedef B (*B_function)();

int main() {
    A_function f1 = A::foo;
    B_function f2 = B::boo;
}

您可以解决它通过从这两个函数中返回基类指针:

class A {
public:
    virtual ~A() = default;      // for destruction via a base class pointer

    static A* foo() { return new A; }
};

class B : A { // you should probably use public inheritance
public:
    static A* boo() { return new B; } // creates a B but returns an A*
};

typedef A* (*function)();

int main() {
    function f1 = A::foo;
    function f2 = B::boo;
}

或者更好,使用智能指针不必手动删除实例:

#include <memory>

class A {
public:
    virtual ~A() = default;

    static std::unique_ptr<A> foo() { return std::make_unique<A>(); }
};

class B : public A {
public:
    static std::unique_ptr<A> boo() { return std::make_unique<B>(); }
};

using function = std::unique_ptr<A>(*)();

int main() {
    function f1 = A::foo;
    function f2 = B::boo;
}

Your function claims that it should return an A but boo returns a B, so:

typedef A (*A_function)();
typedef B (*B_function)();

int main() {
    A_function f1 = A::foo;
    B_function f2 = B::boo;
}

You could possibly solve it by returning a base class pointer from both functions:

class A {
public:
    virtual ~A() = default;      // for destruction via a base class pointer

    static A* foo() { return new A; }
};

class B : A { // you should probably use public inheritance
public:
    static A* boo() { return new B; } // creates a B but returns an A*
};

typedef A* (*function)();

int main() {
    function f1 = A::foo;
    function f2 = B::boo;
}

Or better, using smart pointers to not have to delete instances manually:

#include <memory>

class A {
public:
    virtual ~A() = default;

    static std::unique_ptr<A> foo() { return std::make_unique<A>(); }
};

class B : public A {
public:
    static std::unique_ptr<A> boo() { return std::make_unique<B>(); }
};

using function = std::unique_ptr<A>(*)();

int main() {
    function f1 = A::foo;
    function f2 = B::boo;
}
丑丑阿 2025-02-13 17:55:26

因为bab的孩子

而不是完全。由于ba的孩子,因此任何b对象也是a对象。但是,这不是对称的,因此声称ba的情况正在夸大案例。声称“ a ba>”是正确的,但是删除无限期的文章(“ a”和“ an an”)是错误的。

为什么功能指针从“ void到b”不像“ void到a”的功能指针?

因为b不是a。返回类型不同,因此功能类型不同。 A B可以将对象转换为a对象(通过复制a sub-object),但这是一个额外的步骤。如果要编写

A value = B::boo();

,则编译器将调用b插入a之后的转换 boo()。转换可能不需要机器说明(又称“ no-op”),但是它仍然存在。 (进行转换的一种副作用是,复制不能为 /a>。)

A value = static_cast<A&&>(B::boo());

如果您要通过类型a(*)(*)()()的功能指针调用boo(),则没有什么可以告诉编译器插入转换。跳过转换可能是一个问题,尤其是如果b对象在a对象中没有数据成员,尤其是当这些数据成员具有非平凡的破坏性器时。

该语言不会试图在跳过转换的情况下绘制界限,这不是问题。这同时适用于返回类型和参数类型。分配给指针的函数的类型必须与指针类型完全匹配,不需要转换。


这就是函数对象(例如std :: function)的地方很有用。 std :: function&lt; a()&gt;可以存储a:foob :: booo。这是因为功能对象将适应并记录需要哪些转换,类似于直接调用函数时发生的情况。与功能指针不同,功能对象不需要类型上的确切匹配。

Since B is a child of A, B is A,

Not quite. Since B is a child of A, any B object is also an A object. However, this is not symmetric, so it is overstating the case to claim that B is A. It is correct to claim "a B is an A", but dropping the indefinite articles ("a" and "an") makes the claim false.

why is a function pointer from "void to B" isn't like a function pointer from "void to A"?

Because B is not A. The return types are different, so the function types are different. A B object can be converted to an A object (by copying the A sub-object), but that is an extra step. If you were to write

A value = B::boo();

then the compiler inserts a conversion from B to A after boo() is called. The conversion might not require machine instructions (a.k.a. a "no-op"), but it is there nonetheless. (One side-effect of having a conversion is that copying cannot be elided.)

A value = static_cast<A&&>(B::boo());

If you were to invoke boo() through a function pointer of the type A(*)(), there would be nothing to tell the compiler to insert the conversion. Skipping the conversion could be an issue, particularly if a B object had data members not in A objects, especially if those data members had non-trivial destructors.

The language does not attempt to draw a line between the cases where skipping the conversion is and is not a problem. This applies to both the return type and the parameter types. The type of a function assigned to a pointer must match the pointer's type exactly, no conversions needed.


This is where function objects, like std::function, are useful. A std::function<A()> could store either A:foo or B::boo. This is because the function object will adapt and record what conversions are needed, similar to what happens when invoking a function directly. Unlike a function pointer, a function object does not require an exact match on types.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文