C++ 虚函数之对象切片

对象切片出现在多态处理对象时传值引起的。

传地址之所以不会出现切片因为:地址都相同的长度,派生类对象的地址与基类对象有相同的地址,基类可以透明的操作派生类对象

例如:

#include <stdio.h>
#include <iostream>


using namespace std;


class Pet{
string pName;
public:
Pet(const string& name) :pName(name){}
virtual string name() const{ return pName; }
virtual string describtion() const {
return "this is " + pName;
}
};
class Dog:public Pet
{
string favoriteActivity;
public:
Dog(const string& name, const string& activity) :Pet(name), favoriteActivity(activity){}
string describtion() const {
return Pet::name() + "likes to" + favoriteActivity;
}
};


void describtion(Pet p)
{
string aa = p.describtion();
cout << aa.c_str() << endl;
}


int main()
{


Pet p("Alfred");
Dog g("fluffy", "sleep");
describtion(p);
describtion(g);
getchar();
return 0;
}

运行结果:

this is Alfred

this is fluffy

此时两次均调用了基类,并未调用派生类,1.因为按值传递时编译器知道确切的类型,派生类对象被强转为基类。

2.按值传递时,基类的构造函数被调用,基类构造函数初始化vptr上的vtable,只拷贝基类部分。


当传地址时:

#include <stdio.h>
#include <iostream>

using namespace std;
class Pet{
string pName;
public:
Pet(const string& name) :pName(name){}
virtual string name() const{ return pName; }
virtual string describtion() const {
return "this is " + pName;
}
};
class Dog:public Pet
{
string favoriteActivity;
public:
Dog(const string& name, const string& activity) :Pet(name), favoriteActivity(activity){}
string describtion() const {
return Pet::name() + "likes to" + favoriteActivity;
}
};


void describtion(Pet *p)
{
string aa = (*p).describtion();
cout << aa.c_str() << endl;
}


int main()
{


Pet *p = new Pet("Alfred");
Dog *g = new Dog("full", "sleep");
describtion(p);
describtion(g);
getchar();
return 0;

}



<think>好的,用户想了解C++中的多态概念和虚函数的使用方法。首先,我需要回忆多态的基本定义和类型。多态分为编译时和运行时两种,用户可能更关注运行时多态,因为它涉及虚函数。接下来,虚函数的关键点是什么?比如使用virtual关键字声明,子类重写,以及通过基类指针或引用来调用实现多态。然后,我需要结合用户提供的引用内容。引用1提到多态的三个条件:基类函数必须是虚函数,子类重写的函数签名一致,调用时使用基类指针或引用。引用2则讨论了抽象类和纯虚函数,这可能也是用户需要了解的部分。用户可能想知道如何具体实现这些步骤,比如如何声明虚函数,如何创建派生类,以及如何调用。用户的问题还提到“使用教程”,所以需要给出具体的代码示例,并分步骤解释。可能需要从简单的例子开始,比如Shape类,然后派生Circle和Rectangle,展示如何通过虚函数实现不同的draw方法。此外,要强调多态的优势,比如代码扩展性和维护性。 还要注意用户可能存在的误区,比如忘记将基类函数声明为virtual,或者没有使用指针或引用导致对象切片。此外,纯虚函数和抽象类的概念也需要解释清楚,因为引用2提到了抽象类。可能需要区分虚函数和纯虚函数的不同,以及何时使用它们。 最后,生成的相关问题需要与主题紧密相关,比如多态的实现条件、虚函数与普通成员函数的区别、纯虚函数的作用等。确保问题能帮助用户进一步理解相关内容,并引导他们深入学习。</think>### C++多态与虚函数使用教程 #### 一、多态核心概念 多态分为编译时多态(函数重载/运算符重载)和运行时多态(虚函数实现)。运行时多态需满足三个条件: 1. 基类相关函数必须声明为虚函数(使用$virtual$关键字) 2. 派生类函数必须同名、同返回值、同参数列表 3. 必须通过基类指针或引用调用[^1] $$示例类结构$$ ```cpp class Animal { public: virtual void speak() { cout << "动物叫" << endl; } }; class Cat : public Animal { public: void speak() override { cout << "喵喵" << endl; } }; class Dog : public Animal { public: void speak() override { cout << "汪汪" << endl; } }; ``` #### 二、虚函数使用步骤 1. **基类声明虚函数** ```cpp virtual 返回类型 函数名(参数列表); ``` 2. **派生类重写虚函数** ```cpp // 可显式添加override关键字(C++11) 返回类型 函数名(参数列表) override; ``` 3. **多态调用** ```cpp void makeSound(Animal& animal) { animal.speak(); // 根据实际对象类型调用对应函数 } ``` #### 三、完整示例代码 ```cpp #include <iostream> using namespace std; class Shape { public: virtual void draw() { // 基类虚函数 cout << "绘制基础图形" << endl; } }; class Circle : public Shape { public: void draw() override { // 重写虚函数 cout << "○ 圆形绘制" << endl; } }; class Rectangle : public Shape { public: void draw() override { // 重写虚函数 cout << "□ 矩形绘制" << endl; } }; void render(Shape& shape) { // 通过基类引用调用 shape.draw(); } int main() { Shape base; Circle circle; Rectangle rect; render(base); // 输出:绘制基础图形 render(circle); // 输出:○ 圆形绘制 render(rect); // 输出:□ 矩形绘制 return 0; } ``` #### 四、进阶特性 1. **纯虚函数**(抽象类) ```cpp virtual 返回类型 函数名(参数) = 0; // 强制派生类实现 ``` 2. **虚析构函数** ```cpp virtual ~ClassName() {} // 确保正确释放派生类资源 ``` 3. **override/final关键字**(C++11) ```cpp void draw() override; // 显式声明重写 virtual void draw() final; // 禁止继续重写 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值