智能指针 vs 愚笨指针:多态行为奇异性

3

我正在调试一些较大的代码问题,发现智能指针及其多态属性的一些奇怪之处。最好通过以下简单示例来理解:

#include <iostream>
#include <memory>

using namespace std;

class A {
public:
  virtual void who() {cout << "I am class A" << endl; };
}; 

class B : public A{
public:
  void who() {cout << "I am class B" << endl; };
}; 

int main(int argc, char *argv[])
{
  B b;  
  A * aptr = &b;
  aptr->who(); //Output: I am class B

  B * bptr = &b;
  bptr->who(); //Output: I am class B

  shared_ptr<A> sptr;
  sptr = make_shared<A>(b);
  sptr->who(); //Output: I am class A

  sptr = make_shared<B>(b);
  sptr->who(); //Output: I am class B

  return 0;
}

前两个输出对我来说有意义,但是为什么我可以访问在 A 中定义的成员函数(见第三个输出),当我初始化的对象只是类型 B?从某种意义上说,这是一种访问派生类型对象的基类成员的好方法。然而,对我来说,这仍然有点神秘......

有人能解释为什么智能指针可以实现这种行为,而常规指针却不行吗?


第二行代码 aptr->who(); 应该改为 bptr->who(); - Daniel
如果你真的想要“访问派生类型对象的基类成员”,你只需要执行 sptr->A::who() - aschepler
修正了那个笔误,谢谢! - user2548343
3个回答

11

std::make_shared始终会创建一个全新的对象。

sptr = make_shared<A>(b);

更像是

A* p1 = new A(b);

而不是像

A* p2 = &b;

p1make_shared 的返回值根本没有指向 b


啊,这很有道理。毕竟并不那么可怕! - user2548343

4
下面这句话:
sptr = make_shared<A>(b);

基本上与以下内容相同:

sptr = shared_ptr(new A(b));

你并不是从指向B的指针中创建一个shared_ptr,而是使用A的拷贝构造函数创建了一个新的A对象。


4

make_shared<A>(b) 使用 b 构造一个类型为 A 的对象,并指向该新构造的对象。这会切片 B 对象,因此 shared_ptr 真正指向一个 A


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接