在函数 return 中将 class A 的指针转换为 class B,当 B 具有带“A*”的构造函数时

Converting pointer of class A to class B in function return, when B has constructor with `A*`

在 C++ 中,我们可以 return 来自函数的 A 的指针,其实际 return 值是不同的结构 B,它确实具有第一个对象作为A?

的指针

考虑以下场景。

struct B {
    A* ptr;
    // code...

    B(A* _ptr)
    {
        // code...
    }

};

B foo()
{
    A* tmp;
    // code...
    return tmp;
}

B bar()
{
    A* tmp;
    // code...
    return B(tmp);
}

foo() 方法能正常工作吗?它能调用构造函数吗?

foo()将无法调用构造函数,仅在B按以下方式定义的情况下有效,

struct B {
    A* ptr;
    // code...

    B(A* _ptr) : ptr(_ptr)
    {
        // some code (doesn't changes `ptr`)
    }

};

或按以下方式

struct B {
    A* ptr; // NO more data elements other than `ptr`

    B (A* _ptr) : ptr(_ptr) {
        // some code (doesn't changes `ptr`)
    }
};

如果有效,是因为 B 中的 A* ptr 作为第一个对象吗?

我想知道这在不同的 C++ 版本(<11、11、14、17)上有什么可能性,或者它是否也取决于我使用的编译器。

我想,bar是最好的写法。

我们来测试一下!

#include <iostream>

struct A;

struct B {
    B(A* _ptr)
    {
        std::cout << "I've been called!" << std::endl;
    }

};

B foo()
{
    A* tmp;
    return tmp;
}

int main()
{
    foo();
    return 0;
}

这个简单程序的输出是:

I've been called!

意味着已经调用了构造函数。

有可能,因为B (A* _ptr)是一个转换构造函数。这种类型的构造函数允许自动转换为正在构造的class。


正如@john 提到的,要禁用此行为,我们使用 explicit 说明符。

explicit B(A*)foo() 不再被接受。


此外,如您所见,在我的 B 版本中,没有成员 A* ptr; - 它不是必需的。

进一步了解 Jorengarenar 所说的内容。有时您想禁用此行为。这就是 explicit 关键字的作用

#include <iostream>

struct A;

struct B {
    explicit B(A* _ptr)
    {
        std::cout << "I've been called!" << std::endl;
    }

};

B foo()
{
    A* tmp;
    return tmp;
}

int main()
{
    foo();
    return 0;
}

此版本不再编译。 return tmp; 是一个错误,但 return B(tmp); 会编译并调用构造函数。