gpt4 book ai didi

c++ - 难以理解 C++ 推导

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:10:33 27 4
gpt4 key购买 nike

我将 Java 中的许多假设带到了我对 C++ 的学习中,这似乎再次难倒了我。我没有足够的词汇量来 Eloquent 地说出我希望从以下程序中看到什么,所以我只展示它并说出我希望看到的内容:

#include <iostream>
#include <vector>

using namespace std;

class Piece {};

class Man : public Piece {};

class Square {
Piece p;
public:
Square(Piece p) : p(p) { };
Piece get_piece() const { return p; }
};

ostream& operator<<(ostream& os, const Piece& p)
{
cout << "Piece";
return os;
}

ostream& operator<<(ostream& os, const Man& m)
{
cout << "Man";
return os;
}

ostream& operator<<(ostream& os, const Square& s)
{
cout << s.get_piece() << '\n';
return os;
}

int main()
{
Square sq = Square(Man());
cout << sq;
}

当我运行这个程序时,输出是Piece,但我希望看到Man。这叫运行时多态吗?我以为那是为功能保留的,但我不知道。 Java 中的“等效”程序打印出我所期望的,Man,但我不知道如何让这个 C++ 程序来执行此操作。我错过了什么?

最佳答案

与 Java 不同,C++ 区分对对象和值的引用,即对象本身。当您将派生类型的对象传递给采用基类型值的函数时,您会得到一个切片对象:它将只包含对象基础部分的拷贝,不包含任何派生类型.例如,你的构造函数

Square(Piece piece)

按值获取它的参数,它始终是 Piece 类型,而不是任何派生类型:参数,如果它是派生类型,则被切片。您可以使用像

这样的符号通过引用传递对象
Square(Piece& piece)

如果 piece 引用的对象是可变的或者

Square(Piece const& piece)

如果 piece 引用的对象应该是不可变的。在您的上下文中,您很可能还想处理对象的生命周期管理,这可能最好使用使用 new 在堆上分配并由一些智能指针维护的对象来完成,例如 std: :shared_ptr`。

现在开始你的输出函数:被调用的函数总是基于静态类型静态解析,即在编译期间声明和可见的类型。一旦调用了正确的函数,如果它恰好被声明为 virtual,它会根据对象的动态类型分派(dispatch)到可能的覆盖函数,即虚拟分派(dispatch)是在运行时完成的。出于输出运算符的目的,这意味着它们仅根据静态类型进行选择,在您的情况下始终是 Piece。通常的处理方法是使用一个virtual 函数并从实际的输出运算符分派(dispatch)给这个函数,例如:

class Piece {
protected:
virtual std::ostream& do_print(std::ostream& out) const = 0;
public:
std::ostream& print(std::ostream& out) const { return this->do_print(out); }
};
std::ostream& operator<< (std::ostream& out, Piece const& piece) {
return piece.print(out);
}

class Man: public Piece {
protected:
std::ostream& do_print(std::ostream& out) {
return out << "Man"; // note: you want to use out, not std::cout here
}
};

使用此设置,您可以使用对此类型对象的引用来调用静态输出运算符 Piece,并获得由动态类型选择的输出,例如:

class Square {
std::shared_ptr<Piece> d_piece;
public:
Square(std::shared_ptr<Piece> piece): d_piece(piece) {}
Piece const& get_piece() const { return *this->d_piece; }
};
std::ostream& operator<< (std::ostream& out, Square const& square) {
return out << square.get_piece();
}

print()do_print() 的有点古怪的转发并不是真正需要的,但是如果你有多个 virtual 重载相同的名称并且您只覆盖其中一个,基类中的所有其他版本都会被隐藏。由于 print() 没有被覆盖并且 do_print() 没有被用户调用,隐藏重载的问题有所减少。

关于c++ - 难以理解 C++ 推导,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18294507/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com