2015-02-05 47 views
0

Heyo,当涉及调用对象作为它们的父类型时,我对如何重写方法有点困惑。当使用父类型时覆盖C++方法

这里是我的示例代码:

#include <iostream> 
#include <cstdlib> 
#include <vector> 

using namespace std; 

class A { 
public: 
    A() { 
     std::cout << "Made A.\n"; 
    } 
    void doThing() { 
     std::cout << "A did a thing.\n"; 
    }; 
}; 

class B : public A { 
public: 
    B() { 
     std::cout << "Made B.\n"; 
    } 
    void doThing() { 
     std::cout << "B did a thing.\n"; 
    }; 
}; 

class C : public A { 
public: 
    C() { 
     std::cout << "Made C.\n"; 
    } 
    void doThing() { 
     std::cout << "C did a thing.\n"; 
    }; 
}; 

int main(int argc, char** argv) { 
    std::cout << "\n"; 

    std::cout << "Make objects: \n"; 
    A a; 
    B b; 
    C c; 

    std::cout << "Call objects normally: \n"; 
    a.doThing(); 
    b.doThing(); 
    c.doThing(); 

    std::cout << "Call objects as their parent type from a vector: \n"; 
    vector<A> vect; 
    vect.push_back(a); vect.push_back(b); vect.push_back(c); 

    for(int i=0;i<vect.size();i++) 
     vect.data()[i].doThing(); 

    return 0; 
} 

,这里是输出我得到:

Make objects: 
Made A. 
Made A. 
Made B. 
Made A. 
Made C. 
Call objects normally: 
A did a thing. 
B did a thing. 
C did a thing. 
Call objects as their parent type from a vector: 
A did a thing. 
A did a thing. 
A did a thing. 

在另一种语言(如Java)相同的代码会产生这样的输出:

Make objects: 
Made A. 
Made B. 
Made C. 
Call objects normally: 
A did a thing. 
B did a thing. 
C did a thing. 
Call objects as their parent type from a vector: 
A did a thing. 
B did a thing. 
C did a thing. 

总之,如何在C++中实现第二个输出?

回答

1

每当您将一个Derived对象通过值函数传递给函数Base时,会发生称为“切片”的操作。基本上,只有Derived对象的Base部分被使用。

您需要通过引用或指针传递对象以避免这些问题。例如,声明

f(Base&) 

允许传递一个Derived对象,即允许你写

f(Derived) 

此外,为了使运行时多态性,你的函数必须标明virtual。 Java默认情况下隐含标记为虚拟的一切。但是,这是C++,你不支付你不使用的东西(虚拟函数是开销)。 PS:在你的代码中,即使你想要,你也不能使用std::vector的引用。但是,你可以用使用std::reference_wrapper它允许你以“模拟”引用的std::vector的对象:

std::vector<std::reference_wrapper<A>> vect 

,并使用get成员函数来检索参考

for(int i=0;i<vect.size();i++) 
    vect[i].get().doThing(); 

或者,也许更简单,只是使用一个std::vector<A*>

+0

Righo!更改为“矢量 vect;”并推送数据为“vect.push_back(&b);”结果输出我想要的。谢谢! – 2015-02-05 17:05:10

1

您需要使用virtual关键字才能使函数在子类中被覆盖。

+0

这就是它的一部分。你也不能用值获得多态性,所以向量将不得不存储指针。 – 2015-02-05 16:58:34

+0

我将我的代码更改为virutal void doThing(),但它仍输出相同的内容。有没有使用虚拟的特定方式? – 2015-02-05 16:59:39

+1

@newObjekt:看到我的评论。虽然Java总是在处理对象类型时使用引用,但C++可以使用对象值。但是,如果将派生类的值分配给基类值,则会丢失派生的对象信息。这被称为[切片](http://stackoverflow.com/q/274626/10077)。 – 2015-02-05 17:01:08

1

好吧所以发生了什么事: 使物体: 我觉得很明显。在一个对象被构造和它的默认构造函数打印

Made A 

当你实例化B对象首先它的父类被完全构造。因此,在这种情况下,父类是它就会用默认的构造函数,将B类剩余部分被建成后可打印出

Made A 

并运行它的构造函数,打印出

Made B 

构建实例化时发生同样的事情C

在对象上调用函数: 它只是一个简单的函数调用,因为你覆盖每个类中的函数而不是父函数。

当您创建对象的向量时,您将对象复制到它们中,因为您不通过引用或指针。您还没有写入复制构造函数,因此默认的逐位复制将运行。这种方式从一个B类对象中获得一个A类对象,该类对象的功能将打印出A做过的事情,而不是B做过的事情。同样的情况发生在C.