- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我阅读了 C++ 中的切片问题,并尝试了一些示例(我来自 Java 背景)。不幸的是,我不理解某些行为。目前,我被困在这个例子中(Efficent C++ 第三版的替代例子)。谁能帮我理解一下?
我的简单父类:
class Parent
{
public:
Parent(int type) { _type = type; }
virtual std::string getName() { return "Parent"; }
int getType() { return _type; }
private:
int _type;
};
我的简单 Child 类:
class Child : public Parent
{
public:
Child(void) : Parent(2) {};
virtual std::string getName() { return "Child"; }
std::string extraString() { return "Child extra string"; }
};
主要内容:
void printNames(Parent p)
{
std::cout << "Name: " << p.getName() << std::endl;
if (p.getType() == 2)
{
Child & c = static_cast<Child&>(p);
std::cout << "Extra: " << c.extraString() << std::endl;
std::cout << "Name after cast: " << c.getName() << std::endl;
}
}
int main()
{
Parent p(1);
Child c;
printNames(p);
printNames(c);
}
执行后我得到:
姓名:家长
姓名:家长
额外:子额外字符串
Actor 后的名字: parent
我理解前两行,因为它是“切片”的原因。但我不明白为什么我可以通过静态转换将 child 转换为 parent 。书中写到,切片后,所有的专业信息都会被切片掉。所以我想,我不能将 p 转换为 c,因为我没有信息(在函数 printNames 的开头创建了一个没有附加信息的新父对象) .
此外,如果转换成功,为什么我得到的是“转换后的名字: parent ”而不是“转换后的名字: child ”?
最佳答案
你的结果是非常不幸的一击。这是我得到的结果:
Name: Parent
Name: Parent
Extra: Child extra string
bash: line 8: 6391 Segmentation fault (core dumped) ./a.out
这是您的代码中发生的事情:
当您将 c
传递给 printNames
时,会发生转换。特别是,由于传递是按值传递的,因此您调用了 Parent
的复制构造函数,它是隐式声明的,其代码如下所示:
Parent(Parent const& other) : _type{other._type} {}
换句话说,您复制了c
的_type
变量,没有别的。你现在有一个 new 类型为 Parent
的对象(它的静态和动态类型都是 Parent
)并且 c
是根本没有真正传递给 printNames
。
在函数内部,您随后强制将 p
转换为 Child&
。这个转换不能成功,因为 p
根本不是一个 Child
,也不能转换成一个,但是 C++ 没有给你任何诊断(这实际上是一种耻辱,因为编译器可以简单地证明转换是错误的)。
现在我们处于未定义行为的领域,现在一切都允许发生。实际上,由于 Child::extraString
从不访问 this
(无论是隐式还是显式),对该函数的调用只会成功。该调用是在一个非法对象上完成的,但由于该对象从未被触及,因此有效(但仍然是非法的!)。
下一个对 Child::getName
的调用是一个虚拟调用,因此它需要显式访问 this
(在大多数实现中,它访问虚拟方法表指针)。再一次,因为代码无论如何都是 UB,所以任何事情都可能发生。你很“幸运”,代码只是捕获了父类的虚方法表指针。使用我的编译器,访问显然失败了。
关于c++ - 在我错的地方用 C++ 切片?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25054489/
我无法在附加行中显示“真”、“假”、"is"和“否”按钮。 我在这里有一个应用程序:Application 请按照以下步骤使用应用程序: 1。当你打开应用程序时,你会看到一个绿色的加号按钮,点击 在此
我是一名优秀的程序员,十分优秀!