关于虚函数

当您使用基类指针`p`来调用成员函数时,对于非虚函数,编译器会根据指针的类型(在这里是`A*`)来决定调用哪个函数。对于虚函数,编译器会根据对象的实际类型(在这里是`B`对象)来决定调用哪个函数。

在这段代码中:

```cpp
A *p = &a;
p->foo();  // 输出1,因为p是A类型的指针,所以调用A::foo
p->fun();  // 输出2,因为fun是虚函数,p指向a,所以调用A::fun
p = &b;
p->foo();  // 输出1,即使p现在指向B对象b,foo是非虚函数,所以依然调用A::foo
p->fun();  // 输出4,fun是虚函数,p指向B对象b,所以调用B::fun,体现多态
```

您提到的这一行:

```cpp
p->foo();  // 取决于指针类型,输出1
```

实际上,输出是`1`,这是因为`foo`函数在`A`类中没有被声明为虚函数,所以编译器会根据指针的类型(`A*`)来解析函数调用。即使`p`指针后来被赋值为指向`B`对象,调用`foo`函数时仍然会调用`A::foo`,因为`foo`不是虚函数,编译器不会考虑对象的实际类型。

如果您希望`foo`函数在派生类`B`中被覆盖,您需要在基类`A`中将其声明为虚函数:

```cpp
class A  
{  
public:  
    virtual void foo()  // 声明为虚函数
    {  
        printf("1\n");  
    }  
    virtual void fun()  
    {  
        printf("2\n");  
    }  
};
```

在这种情况下,当`p`指向`B`对象时,调用`foo`函数将会输出`3`,因为`B::foo`现在是`A::foo`的覆盖版本,且`foo`是虚函数,所以编译器会根据对象的实际类型解析函数调用。

注意使用指针时,是根据 指针的类型(`A*`)来解析函数调用。即使`p`指针后来被赋值为指向`B`对象,调用`foo`函数时仍然会调用`A::foo`,因为`foo`不是虚函数,编译器不会考虑对象的实际类型。

而不使用指针时比如以下这种情况:跟指针是不同的 !!:直接创建对象并调用函数。

class Base {
public:
    void func() {
        std::cout << "Base class func" << std::endl;
    }
};

class Derived : public Base {
public:
    void func() { // 这个函数屏蔽了基类中的func
        std::cout << "Derived class func" << std::endl;
    }
};

int main() {
    Derived d;
    d.func(); // 调用的将是Derived类中的func,输出: Derived class func
    // Base类的func被屏蔽,无法通过Derived对象d直接调用
    return 0;
}

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ,函数是指一个函数,它在派生类中被重新定义,但在基类中不能使用。它可以被用来实现多态,因为它允许派生类重写基类的行为。例如,假设有一个基类Animal,它有一个函数makeSound,它在派生类中被重写,以便每个派生类都可以定义自己的声音。 ### 回答2: 函数是C++面向对象编程中的重要概念,它允许子类重写父类的成员函数,实现多态性。通过函数,我们可以在编译时期无需知道对象的实际类型,而直接调用相应的成员函数。 举个例子来说明函数的应用:假设我们有一个动物类Animal,它有一个纯函数eat(),用于描述动物的进食行为。然后我们派生出了两个子类Cat和Dog,并对eat()函数进行了重写,以实现不同动物的进食行为。 ```cpp #include <iostream> using namespace std; class Animal { public: virtual void eat() = 0; // 纯函数 }; class Cat : public Animal { public: void eat() { cout << "猫吃鱼!" << endl; } }; class Dog : public Animal { public: void eat() { cout << "狗吃骨头!" << endl; } }; int main() { Animal* animal; Cat cat; Dog dog; animal = &cat; animal->eat(); // 输出:猫吃鱼! animal = &dog; animal->eat(); // 输出:狗吃骨头! return 0; } ``` 在上述代码中,Animal类是一个抽象类,其中的eat()函数被声明为纯函数。纯函数没有具体的实现,必须由派生类来实现。Cat和Dog两个子类分别实现了eat()函数,用于描述猫和狗的进食行为。 在main函数中,我们通过Animal指针多态的方式来调用不同派生类的eat()函数,实现了动态绑定。当animal指向cat时调用eat()函数输出"猫吃鱼!",而当animal指向dog时调用eat()函数输出"狗吃骨头!"。这也展示了函数的多态性质。 ### 回答3: 函数是面向对象编程中重要的概念之一,它允许派生类通过重写基类的函数来实现自己的特殊行为。 举个例子,我们可以考虑一个"动物"的基类Animal,它有一个函数"发出声音"(makeSound)。动物类的派生类比如"狗"(Dog)和"猫"(Cat)都继承了基类Animal,并重写了"发出声音"这个函数。 在基类Animal中,函数"发出声音"只是简单的输出一个基本的动物声音,比如"动物发出了声音!"。而在派生类Dog中,"发出声音"被重写为输出"汪汪汪!",代表狗的声音。同样,在派生类Cat中,"发出声音"被重写为输出"喵喵喵!",代表猫的声音。 当我们创建一个基类Animal的实例时,我们可以调用它的"发出声音"函数,输出的是基类的默认声音。但是,当我们创建一个派生类Dog或Cat的实例,并调用它们的"发出声音"函数时,会分别输出狗和猫的特定声音。 通过函数,我们可以实现面向对象编程的多态性,即通过基类的指针或引用来访问派生类的特定行为。这是因为在运行时,程序会动态地选择正确的函数执行。 总结而言,函数是一种能够在基类和派生类之间建立动态联编关系的机制,可以实现多态行为,在不同的派生类中重写函数实现特定的行为。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值