多态性 c++ 错误输出

Polymorphism c++ wrong output

本文关键字:输出 错误 c++ 多态性      更新时间:2023-10-16

为什么此代码的输出是 A 类 我希望看到"AAA 类"

#include <iostream>    
using namespace std;
class A
{
    public:
    A(){}
    virtual int Method1(int a, int b){cout << "Class A" << endl; return a+b;    }
};
class AA:public A
{
    public:
    AA(){}
    int Method1(int a, int b){cout << "Class AA" << endl; return a*b;}
};
class AAA:public A
{
    public:
    AAA(){}
    int Method1(int a, int b){cout << "Class AAA" << endl; return a/b;}
};
class B
{
public:
   B(){}
   B(A a):obj(&a){}
   int Method2(int a, int b){ return obj->Method1(a,b);}
private:
    A *obj;
};
int main() {
    A *a = new AAA();
    B *b = new B(*a);
    b->Method2(2,1);
    return 0;
}

我有新的 AAA 对象传递给 B 类并分配给 *obj。这是怎么回事?此致敬意

您正在切片传递给B()构造函数的对象,因此B看到的只是A的实例,而不是AAA的实例。

多态性仅在通过指针/引用访问派生对象时才有效,因此可以访问虚拟方法的完整 vtable。 这也包括在传递派生对象时。 如果按值将派生类传递给基类变量/参数,则将对对象进行切片,并且变量/参数将只能访问基类 vtable 条目。

因此,您需要相应地更改B,如下所示:

class B
{
public:
   B() : obj(0) {} // <-- every constructor needs to initialize members!
   B(A *a) : obj(a) {} // <-- accept A by pointer
   int Method2(int a, int b) { return (obj) ? obj->Method1(a,b) : 0; }
private:
    A *obj;
};
int main() {
    A *a = new AAA();
    B *b = new B(a); // <-- AAA passed by A* pointer
    b->Method2(2,1);
    // don't forget these
    delete b;
    delete a;
    return 0;
}

或者这个:

class B
{
public:
   B() : obj(0) {} // <-- every constructor needs to initialize members!
   B(A &a) : obj(&a) {} // <-- accept A by reference
   int Method2(int a, int b) { return (obj) ? obj->Method1(a,b) : 0; }
private:
    A *obj;
};
int main() {
    A *a = new AAA();
    B *b = new B(*a); // <-- AAA passed by A& reference
    b->Method2(2,1);
    // don't forget these
    delete b;
    delete a;
    return 0;
}

甚至这个:

class B
{
public:
   // <-- note: no default constructor!
   B(A &a) : obj(a) {} // <-- accept A by reference
   int Method2(int a, int b) { return obj.Method1(a,b); }
private:
    A &obj;
};
int main() {
    A *a = new AAA();
    B *b = new B(*a); // <-- AAA passed by A& reference
    b->Method2(2,1);
    // don't forget these
    delete b;
    delete a;
    return 0;
}

在任何情况下,请注意,A需要一个虚拟析构函数,以便在指针或A&引用的基类A*调用delete时可以正确调用派生析构函数:

class A
{
public:
    ...
    virtual ~A() {} // <-- add this
    ...
};

如果您使用的是 C++11 或更高版本,则应使用 std::unique_ptrstd::shared_ptr 而不是原始指针,让编译器为您处理 (de) 分配:

#include <memory>
class B
{
public:
   B(std::shared_ptr<A> &a) : obj(a) {}
   int Method2(int a, int b) { return obj->Method1(a,b); }
private:
    std::shared_ptr<A> obj;
};
int main() {
    std::shared_ptr<A> a(new AAA);
    std::unique_ptr<B> b(new B(a));
    // or: if you are using C++14 or later:
    /*
    std::shared_ptr<A> a = std::make_shared<AAA>();
    std::unique_ptr<B> b = std::make_unique<B>(a);
    */
    b->Method2(2,1);
    return 0;
}