在下面的代码中,函数foo是从派生对象d复制构造一个基础对象c。我的问题是:我们要得到确切的副本吗?因为我没有得到期望的多态行为
#include<iostream>
class Base
{
public:
virtual void sayHello()
{
std::cout << "Hello Base" << std::endl ;
}
};
class Derived: public Base
{
public:
void sayHello() override
{
std::cout << "Hello Derived" << std::endl ;
}
};
void foo(Base* d)
{
Base* c = new Base(*d);
c->sayHello() ;
}
int main()
{
Derived d;
foo(&d) ; //outputs Hello Base
}
答案 0 :(得分:2)
没有virtual
构造函数,也没有复制构造函数。
但是,可以定义一个行为类似的函数。
在我的情况下,这是我添加到OP示例中的virtual
成员函数copy()
:
#include <iostream>
class Base
{
public:
virtual Base* copy() const { return new Base(*this); }
virtual void sayHello()
{
std::cout << "Hello Base" << std::endl ;
}
};
class Derived: public Base
{
public:
virtual Base* copy() const override { return new Derived(*this); }
void sayHello() override
{
std::cout << "Hello Derived" << std::endl ;
}
};
void foo(Base* d)
{
Base* c = d->copy();
c->sayHello() ;
}
int main()
{
Derived d;
foo(&d) ; //outputs Hello Derived
return 0;
}
输出:
Hello Derived
缺点是Base
的每个派生类都必须提供它才能使其正常运行。 (我不知道如何用任何技巧说服编译器为我进行检查。)
部分解决方案可能是使copy()
中的class Base
纯虚拟(假设它不是可实例化的)。
答案 1 :(得分:1)
您可能会更改新行
Base* c = new Derived(*d);
,因此在Base指针中具有Derived类型。在运行时,将查找它的类型,并获得正确的输出。
让我知道我是否做错了...只是在飞行过程中突然想到的。
答案 2 :(得分:1)
要回答有关是否是复制构造的问题,请添加一些成员。 Base
将有一个成员,m_b
和Derived
将继承m_b
但也有另一个成员m_d
#include <iostream>
struct Base {
const int m_b;
Base() = delete;
Base(const int a_b) : m_b(a_b) {}
virtual void sayHello() {
std::cout << "Base " << m_b << std::endl;
}
};
struct Derived : public Base {
const int m_d;
Derived() = delete;
Derived(const int a_b, const int a_d) : Base(a_b), m_d(a_d) {}
void sayHello() override {
std::cout << "Derived " << m_b << ' ' << m_d << std::endl;
}
};
void foo(Derived* a) {
Base* b = new Base(*a);
b->sayHello(); // Output is "Base 1", 1 was copied from argument a
}
void bar(Derived* a) {
Base* d = new Derived(*a);
d->sayHello(); // Output is "Derived 1 2"
}
int main() {
Derived d(1, 2);
foo(&d);
bar(&d);
return 0;
}
该行:
Base* b = new Base(*a);
创建了Base
,因此sayHello
调用了Base
的实现,而该实现不了解m_d
。但是,此行确实从派生类中复制了m_b
该行:
Base* d = new Derived(*a);
创建了Derived
,因此sayHello
调用了Derived
的实现,该实现复制了m_b
和m_d
答案 3 :(得分:0)
当Base
类指针指向Derived
类对象时,将出现预期的多态行为。然后在运行时,将检查Base
类指针指向的对象的实际类型,并调用适当的函数。
Base* c = new Base(*d); // <<-- case of object slicing
在这里,c
指向Base
类对象。因此,c->sayHello() ;
势必在运行时调用Base::sayHello()
。
are we getting an exact copy?
。否,因为由于Base
而创建了new Base
对象。由于对象切片,Base
对象的*d
部分被传递到copy c'tor
,并且您得到的是对应的Base
对象。
Base *c = new Derived(*d);
将给出预期的行为。