将基数转换为派生 class

Converting base to derived class

在下面的代码中,虽然 subclass 的实例被压入 base class 的堆栈,但是在检索(顶部操作)一个元素并将其存储在派生的 class 对象,编译器正在生成错误。

#include <cstdio>
#include <stack>

using namespace std;

class base{};

class sub : public base{
public:
    int a;
    sub (int A){ a=A;}
};

int main(){
    stack<base> st;

    sub A = sub(10);
    sub B = sub(20);

    st.push(A);
    st.push(B);
    printf("%d\n", (int)st.size());

    sub C = (sub)st.top();

    return 0;
}

错误:

 In function ‘int main()’:  
24:22: error: no matching function for call to ‘sub::sub(base&)’  
24:22: note: candidates are:  
11:2: note: sub::sub(int)  
11:2: note:   no known conversion for argument 1 from ‘base’ to ‘int’  
8:7: note: sub::sub(const sub&)  
8:7: note:   no known conversion for argument 1 from ‘base’ to ‘const sub&’  

请建议我可以将检索到的基础 class 对象类型转换为派生的 class。

这是一个预期的错误,自然是因为 class base 的对象和 class sub 的另一个对象与编译器不同。当您将右值 a 等同于另一个值 b 时,您是在调用 acopy-constructor 时将 b 作为参数。默认情况下,如果您不在 class 声明中实现此功能,C++ 将对 a 中的成员执行 b 的每个成员副本。但是,如果 ab 是不同的类型,编译器将复制哪些成员是不明确的,即使一个是从另一个派生的(因为它总是有可能会有额外的成员) , 从而增加大小并改变对象 class 的结构)。

正如 Joachim 在评论中回答的那样,要使多态性起作用,您需要处理指针或引用。你不能使用引用,因为你不能有引用的容器。

stack<base*> st;

sub A = sub(10);
sub B = sub(20);

st.push(&A);
st.push(&B);
printf("%d\n", (int)st.size());

sub *C = (sub*)st.top();

std::stack 这样的标准容器应该存储 指向基 class 的指针,这些指针指向动态分配的子 class 对象。在现代 C++ 中,建议您为此自动进行内存管理,使用 std::unique_ptr.

std::unique_ptrs 应该用 std::make_unique 创建。 A std::unique_ptr 不能复制,只能移动。当您将未命名的临时变量传递给堆栈的 push 函数时,这会自动发生。

std::unique_ptr(不像std::shared_ptr)也需要一个虚析构函数。但这应该不是问题,因为您首先使用基 class 和派生 class 的原因应该是您的代码不需要知道派生类型但只使用基本类型的虚函数。 (如果您只需要在 sub 中访问 base 的实现,那么 public 继承无论如何都是错误的工具。)

这是一个完整的示例(我还修复了您代码中的其他一些问题):

#include <stack>
#include <memory>
#include <iostream>

// using namespace std; is bad practice --> removed

class base {
public:
    virtual ~base() {}
};

class sub : public base{
public:
    int a;
    sub (int A) : a(A) {} // initialisation list rather than assignment
};

int main(){
    std::stack<std::unique_ptr<base>> st;

    st.push(std::make_unique<sub>(10));
    st.push(std::make_unique<sub>(20));
    std::cout << st.size() << "\n"; // no more printf

    auto const& C = *(st.top()); // using C++11 auto

    // no return 0 necessary in main
}

现在,C 是基类型的引用。

如果由于某种原因,你确实需要访问底层sub,那么你可以这样做:

auto const& C = dynamic_cast<sub const&>(*(st.top()));
std::cout << C.a << "\n";

它很丑陋,但是假设一个具体的子class的整个概念通常是一个设计缺陷,所以代码的丑陋符合概念。