class CAnimal
{
public:
virtual void CallFunc(){
cout << "animal......";
}
private:
string m_name;
};
class CCat : public CAnimal
{
public:
virtual void CallFunc() override {
cout << "miaomiaomiao......";
}
private:
string m_name;
};
class CDog : public CAnimal
{
public:
virtual void CallFunc() override {
cout << "wangwangwang......";
}
private:
string m_name;
};
void testFunc(CAnimal obj) {
obj.CallFunc();
}
int main()
{
std::cout << "Hello World!\n";
CCat cat;
testFunc(cat);
}
执行结果:
将testFunc函数中参数传递的方式改变一下,改成引用传递。
void testFunc(CAnimal &obj) {
obj.CallFunc();
}
执行结果:
改成指针传递:
void testFunc(CAnimal *obj) {
obj->CallFunc();
}
执行结果:
会产生这种现象的原因是:
-
值传递(
void testFunc(CAnimal obj)
): 当你传递一个对象给函数时,会创建该对象的一个副本,而不是引用原始对象。在这种情况下,如果你传递一个CCat
对象给testFunc
,会发生切片(slicing)现象,即只有CAnimal
部分的内容会传递给函数。因此,虽然你传递了一个CCat
对象,但函数内部处理的是一个CAnimal
对象的副本,因此无法实现多态,因为它只知道调用CAnimal
的CallFunc
。 -
引用传递(
void testFunc(CAnimal &obj)
): 当你传递一个对象的引用给函数时,函数操作的是原始对象,而不是对象的副本。这使得多态能够正常工作,因为它能够识别对象的实际类型,而不仅仅是基类类型。所以,在这种情况下,如果你传递一个CCat
对象给testFunc
,它会调用CCat
类的CallFunc
方法,实现了多态性。 -
指针传递(
void testFunc(CAnimal *obj)
):也可以实现多态,原因在于指针引用了原始对象而不是创建对象的副本,这也符合多态的概念。引用传递(void testFunc(CAnimal &obj)
)和指针传递(void testFunc(CAnimal *obj)
)的核心思想是一致的,它们都让函数能够访问原始对象,而不是对象的副本。在void testFunc(CAnimal *obj)
中,你传递了一个指向CAnimal
或其派生类的指针。在运行时,这个指针可以指向任何CAnimal
派生类的对象。因为指针是多态的,它会调用实际对象的成员函数,而不仅仅是基类的成员函数。所以,如果你传递一个CCat
对象的指针给testFunc
,它会调用CCat
类的CallFunc
方法,实现了多态性。
总之,无论是引用传递还是指针传递,它们都允许函数访问原始对象,从而实现多态性。这两种方式都是在函数内部操作原始对象,而不是对象的副本,因此都能正确处理派生类的成员函数调用。而使用值传递会导致对象切片,丧失了多态性。因此,如果你想实现多态性,应该使用引用传递或指针传递,而不是值传递。