C++ 在不处理指针时调用子类(虚拟)函数(后期绑定)
看看答案,他们表明虚拟函数允许后期绑定,这导致在降级时能够调用子类函数 为了完整性,我加入了有问题的代码C++ 在不处理指针时调用子类(虚拟)函数(后期绑定),c++,pointers,inheritance,C++,Pointers,Inheritance,看看答案,他们表明虚拟函数允许后期绑定,这导致在降级时能够调用子类函数 为了完整性,我加入了有问题的代码 class Animal { public: virtual void eat() { std::cout << "I'm eating generic food."; } }; class Cat : public Animal { public: void eat() { std::cout << "I'm eating a ra
class Animal
{
public:
virtual void eat() {
std::cout << "I'm eating generic food.";
}
};
class Cat : public Animal
{
public:
void eat() { std::cout << "I'm eating a rat."; }
};
我们看到调用func会导致
Animal *animal = new Animal;
Cat *cat = new Cat;
func(animal); // outputs: "I'm eating generic food."
func(cat); // outputs: "I'm eating a rat."
Animal animal;
Cat cat;
func2(animal); // outputs: "I'm eating generic food."
func2(cat); // outputs: "I'm eating generic food."
调用func2时会导致
Animal *animal = new Animal;
Cat *cat = new Cat;
func(animal); // outputs: "I'm eating generic food."
func(cat); // outputs: "I'm eating a rat."
Animal animal;
Cat cat;
func2(animal); // outputs: "I'm eating generic food."
func2(cat); // outputs: "I'm eating generic food."
我的问题是:
我怎样才能使接收参数(不是指针)的函数使用重写的方法呢?换句话说,func2怎么会导致“我在吃老鼠”。此外,我想了解为什么会出现这种差异。我先谢谢你
我怎样才能使接收参数(不是指针)的函数使用重写的方法呢?换句话说,func2怎么会导致“我在吃老鼠”
您可以使用引用而不是指针
void func2(Animal& xyz) { xyz.eat(); }
然后,使用
Animal animal;
Cat cat;
func2(animal);
func2(cat);
会像你希望的那样工作
此外,我想了解为什么会出现这种差异
这是由对象切片引起的。请参阅了解对象切片是什么,以及如何在代码中发挥作用。 < P> C++中的整个虚函数机制是基于选择实际函数来调用的,该函数是基于调用中使用的对象的动态(“实际”)类型调用的。在这个函数中
void func2(Animal xyz) { xyz.eat(); }
xyz
对象的类型是Animal
。它被明确硬编码为动物
。它的静态类型是Animal
。其动态类型为Animal
。它在各个方面都是动物。您自己要求编译器使用上述参数声明来实现这一点
这意味着
xyz.eat()代码>调用将始终调用动物::eat()
。这是没有办法的。没有办法让它调用Cat::eat()
,因为这里没有Cat
对象。通过将Cat
作为实际参数传递,您只需要求编译器从该Cat
生成Animal xyz
,然后忽略原始Cat
。(这通常被称为“切片”。)所有后续工作都是使用动物xyz
完成的。原因是func2
函数不使用传递给它的对象。该函数有自己的参数变量Animal xyx
,该变量由Animal
或cat
变量构成。因此,在func2
中,始终有一个基类对象要处理,因此该函数始终调用通用答案
void func2(Animal xyz) // uses its own Animal xyz, created on call
{
xyz.eat(); // uses a local xyz object of Animal class with its generic functions
}
Cat cat;
func2(cat); // here a new Animal xyz is created from the cat
必须将实际对象的指针或引用作为参数传递给函数,以允许函数访问对象的特定重写虚拟函数。像这样:
void func2(Animal& xyz) // uses a reference to the argument object
{
xyz.eat(); // the actual argument is used with its overridden functions
}
Cat cat;
func2(cat); // the cat is passed to the callee
可以使用值语义实现类。那么你就不需要指针或引用了。看肖恩父母的“”这可能会让你大吃一惊。观看演讲,了解他如何使用值语义来避免糟糕的数据共享,并实现一个令人印象深刻的多态撤销系统。下面是一个带注释的示例:
// A generic draw function that any type that streams to std::ostream can use
template <typename T>
void draw(const T& x, ostream& out, size_t position)
{
out << string(position, ' ') << x << endl;
}
// A class that can hold anything with value semantics
// -- note: no virtual functions and no inheritance!
class object_t {
// ... see the talk for the details here ...
// This is where the magic happens
};
// Define a vector of our object_t to be a document
using document_t = vector<object_t>;
// Overload the draw() function for document - just iterate
// through the vector and call draw() on each item in it
void draw(const document_t& x, ostream& out, size_t position)
{
out << string(position, ' ') << "<document>" << endl;
for (auto& e : x) draw(e, out, position + 2);
out << string(position, ' ') << "</document>" << endl;
}
// Define my own class that the code above knows nothing
// about and that doesn't inherit from object_t
class my_class_t {
/* ... */
};
// Overload draw for it
void draw(const my_class_t&, ostream& out, size_t position)
{ out << string(position, ' ') << "my_class_t" << endl; }
// Use all this stuff
int main()
{
document_t document; // just a vector!
// Add some objects that don't inherit from object_t!
document.emplace_back(0);
document.emplace_back(string("Hello!"));
// Show what we've got so far
draw(document, cout, 0);
// Add some more stuff
document.emplace_back(document); // Add a whole copy of the current doc!
document.emplace_back(my_class_t()); // Add an arbitrary type that doesn't inherit from object_t!
draw(document, cout, 0);
}
//流式传输到std::ostream的任何类型都可以使用的通用绘图函数
模板
空心图纸(常数T&x、横截面和横截面、尺寸和位置)
{
谢谢你的回答。有没有可能以这种方式重新编写代码,这样就不需要引用了?我正在处理的是实现两个类,其中需要一般行为。@LeastSquaresWonder,要获得动态分派或延迟绑定(如你所说),你需要传递指针或引用。你无法获得如果你传递了一个对象,动态调度。阅读对象切片以了解原因。