C++中的多态性不能与引用一起正常工作
Polymorphism in C++ does not work correctly with reference
我有一个简单的代码,它不能正确使用引用(多态性)。
#include <iostream>
#include <string>
class Base {
public:
Base() {}
virtual ~Base() {}
virtual std::string text() const {
return "Base";
}
};
class Derived: public Base {
public:
Derived(Base& _b): b(_b) {}
virtual ~Derived() {}
virtual std::string text() const {
return b.text() + " - Derived";
}
private:
Base& b;
};
int main(int argc, char const *argv[])
{
Base b;
Derived d1(b);
std::cout << d1.text() << std::endl;
Derived d2(d1);
std::cout << d2.text() << std::endl;
return 0;
}
输出:
Base - Derived
Base - Derived
我期望输出中的第二行:Base - Derived - Derived
。我阅读了一些资源,多态性与引用和指针完美地结合在一起,但在这种情况下,它不是。如果我用指针替换引用,它会再次工作。有人能给我解释一下吗?
非常感谢!
您正在调用Derived
的默认复制构造函数。因此,当完成时,d2
将是d1
的简单成员副本,并且它们的两个b
成员将引用相同的Base
实例。
要证明这一点,请将其添加到您的Derived
类中
class Derived: public Base {
public:
Derived(Derived& d) : b(d) {}
Derived(Base& _b): b(_b) {}
virtual ~Derived() {}
virtual std::string text() const {
return b.text() + " - Derived";
}
private:
Base& b;
};
有了这个,你的输出将变成:
Base - Derived
Base - Derived - Derived
请注意,这并不是一个伟大的想法,也不是多态性的一个出色的学习例子。(但这是一个有趣的构建覆盖的例子)。还要注意,这不是默认副本构造的典型覆盖(其中参数是const-ref类型)。因此,这不是最大样本的部分原因。
如果您对代码进行指令,您将在调用Derived d2(d1)
时看到Derived::Derived(Base&)构造函数未被调用。这是因为d1参数与隐式复制构造函数,它只是将b成员从d1复制到d2。
为了查看预期的行为,可以显式地将d1强制转换为(Base&)d1
。如果你这样做因此,您将获得如下代码(使用仪器):
#include <iostream>
#include <string>
class Base {
public:
Base() {}
virtual ~Base() {}
virtual std::string text() const {
return "Base";
}
};
class Derived: public Base {
public:
Derived(Base& _b): b(_b) {std::cout << "init'ed with: " << _b.text() << std::endl;}
virtual ~Derived() {}
virtual std::string text() const {
return b.text() + " - Derived";
}
private:
Base& b;
};
int main(int argc, char const *argv[])
{
std::cout << "Creating Base" << std::endl;
Base b;
std::cout << "Creating d1" << std::endl;
Derived d1(b);
std::cout << d1.text() << std::endl;
std::cout << "Creating d2" << std::endl;
Derived d2(d1);
std::cout << d2.text() << std::endl;
std::cout << "Creating d3" << std::endl;
Derived d3((Base&)d1);
std::cout << d3.text() << std::endl;
return 0;
}
这给出了预期的输出:
Creating Base
Creating d1
init'ed with: Base
Base - Derived
Creating d2
Base - Derived
Creating d3
init'ed with: Base - Derived
Base - Derived - Derived
您的d1
和d2
都具有类型Derived
,因此可以正常工作。通常,引用是颠倒的;例如
Base b;
Derived d;
Base &dr = d;
std::cout << b.text() << std::endl;
std::cout << dr.text() << std::endl;
这里text()
是通过Base
类型调用的,但后者将调用Derived
中的版本。
请注意,允许通过基类初始化派生类通常是没有意义的。假设您添加的类型Derived2
的能力或状态与Derived
大不相同。此构造函数将允许
Derived2 d2;
Derived d1(d2);
这可能是一个非常糟糕的主意。
正如注释中正确指出的那样,它现在使用默认的复制构造函数,这就是您观察到两者输出相同的原因。因此,d1只是复制到d2中,而不是用于d2中的基成员变量。
- QSqlquery prepare()和bindvalue()不工作
- 导入库可以跨dll版本工作吗
- 以螺旋方式打印矩阵的程序.(工作不好)
- 对象指针在c++中是如何工作的
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- C++为线程工作动态地分割例程
- 为什么我的 std::ref 无法按预期工作?
- 布尔比较运算符是如何在C++中工作的
- SampleConsensusPrerejective(ext.RANSAC)是如何真正工作的
- 不确定要在我的main中放入什么才能使我的代码正常工作
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- <<操作员在下面的行中工作
- 有人能解释一下为什么下界是这样工作的吗C++的
- ExtractIconEx:可以工作,但偶尔会崩溃
- C++中的memset函数工作不正常
- 当我在第一个循环中使用"auto"时,它工作正常,但是使用"int"它会给出错误,为什么?
- 为什么STD ::计数将常数传递给Lambda,而不是在弦上工作时而不是字符
- C++程序已停止工作-求解常微分方程