Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/161.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 共享指针本质上并不强制转换为基/派生类型_C++_C++11_Inheritance_Casting_Shared Ptr - Fatal编程技术网

C++ 共享指针本质上并不强制转换为基/派生类型

C++ 共享指针本质上并不强制转换为基/派生类型,c++,c++11,inheritance,casting,shared-ptr,C++,C++11,Inheritance,Casting,Shared Ptr,我所做的:我最近开始编写一个多线程生产者-消费者风格的队列。起初,我使用智能指针,但最终将它们全部更改为原始指针,并手动管理它们的生命周期和内存管理(如果有兴趣,请在最后编写代码) 我在寻找什么:支持或反对这个猜想的论据: 继承不能像对待原始指针和引用对象那样,与共享指针放在同一个房间里 我的推理: Base和派生的对象是协变的。原始指针(Base*和Derived*)也是如此。共享指针(Shared_ptr和Shared_ptr)不可用 程序员必须使用dynamic\u pointer\u c

我所做的:我最近开始编写一个多线程生产者-消费者风格的队列。起初,我使用智能指针,但最终将它们全部更改为原始指针,并手动管理它们的生命周期和内存管理(如果有兴趣,请在最后编写代码)

我在寻找什么:支持或反对这个猜想的论据:

继承不能像对待原始指针和引用对象那样,与共享指针放在同一个房间里

我的推理:
Base
派生的
对象是协变的。原始指针(
Base*
Derived*
)也是如此。共享指针(
Shared_ptr
Shared_ptr
)不可用

程序员必须使用
dynamic\u pointer\u cast
进行许多概念上不必要的向下转换,这使得代码很难看,并且在编译时和运行时都有点昂贵

这让我想知道,在面向对象的设计中是否应该避免使用共享指针,因为它们的好处并不超过它们的花费和头痛


更改前我的代码(为了可读性,省略了多线程):

typedef共享\u ptr动物\u ptr;
typedef共享狗;
类缓冲区{
私人:
互斥;
条件变量条件;
德克缓冲区;
公众:
无效添加(共享请求){
标准:独特的锁柜(mu);
cond.wait(locker,[this](){返回缓冲区大小()0;});
shared_ptr back=缓冲区_u.back();
buffer_u.pop_back();
locker.unlock();
条件通知所有人();
}
};
int main(){
缓冲区;
animal_ptr bPtr1(new animal());//buffer.add()工作正常
dog_ptr dPtr1(new dog());//编辑:也可以。
动物_ptrdptr2(新狗());//编辑:没关系
...
buffer.remove();//返回基类对象,需要向下转换才能访问派生成员
} 编辑了解更多信息,以及为什么共享指针对待继承的方式不同于原始指针:

void func1(shared_ptr<Animal> ptr);
void func2(Animal* ptr);
...
Dog* rawPtr = new Dog();
func1(dPtr1); // is not possible, requires upcasting
func2(rawPtr); // is ok.
void func1(共享函数);
无效功能2(动物*ptr);
...
狗*rawPtr=新狗();
功能1(dPtr1);//不可能,需要向上投射
func2(rawPtr);//可以。

现在我了解了您面临的问题。如果您在任何地方都始终使用shared_ptr,那么就能够传递与原始指针相同的Base和派生的shared_ptr对象。我充实了你举的例子

当您混合使用共享指针和原始指针时,问题就出现了。第一个问题与重载有关,其中共享的_ptr函数将转发给执行实际工作的原始指针的函数。当使用从共享指针获得的底层原始指针进行调用时,第二个问题就消失了

class Animal
{
public:
};

class Dog : public Animal
{
public:
};

using std::shared_ptr;

typedef shared_ptr<Animal> animal_ptr;
typedef shared_ptr<Dog> dog_ptr;

class Buffer {
private:
    std::deque<shared_ptr<Animal> > buffer_;
public:
    void add(shared_ptr<Animal> req) {
        buffer_.push_back(req);
    }

    shared_ptr<Animal> remove() {
        shared_ptr<Animal> back = buffer_.back();
        buffer_.pop_back();
    }
};

void func1(Animal* ptr)
{}

void func1(shared_ptr<Animal> ptr)
{
    func1(ptr.get());
}

void func2(Animal* ptr)
{}


int main() 
{
    Buffer buffer;
    animal_ptr bPtr1(new Animal()); // buffer.add() works just fine
    dog_ptr    dPtr1(new Dog());    // requires upcasting before buffer.add()
    animal_ptr dptr2(new Dog());    // returns error, as they are covariant

    Dog* rawPtr = new Dog();
    func2(rawPtr); // is ok.
    func1(dPtr1); // is ok.

    func1(rawPtr); // requires overloading func1 with shared_ptr and raw pointer signatures
    func2(dPtr1.get()); // is okay when using underlying raw ptr

    return 0;
}
类动物
{
公众:
};
犬类:公共动物
{
公众:
};
使用std::shared_ptr;
typedef共享动物;
typedef共享狗;
类缓冲区{
私人:
标准::德克缓冲区;
公众:
无效添加(共享请求){
缓冲区推回(req);
}
共享\u ptr remove(){
shared_ptr back=缓冲区_u.back();
buffer_u.pop_back();
}
};
无效功能1(动物*ptr)
{}
无效功能1(共享\u ptr ptr)
{
func1(ptr.get());
}
无效功能2(动物*ptr)
{}
int main()
{
缓冲区;
animal_ptr bPtr1(new animal());//buffer.add()工作正常
dog_ptr dPtr1(new dog());//需要在buffer.add()之前向上转换
animal_ptr dptr2(new Dog());//返回错误,因为它们是协变的
狗*rawPtr=新狗();
func2(rawPtr);//正常。
func1(dPtr1);//正常。
func1(rawPtr);//需要使用共享的\u ptr和原始指针签名重载func1
func2(dPtr1.get());//在使用底层原始ptr时可以
返回0;
}
不,它可以工作。
http://coliru.stacked-crooked.com/a/b2a83c740ed60521
#包括
#包括
结构A{
void print(){std::cout A::print();
//这管用!
打印(ptr_a);
打印(ptr_b);
}
最后两个“A”正确打印。函数无法工作的原因是因为
Dog*!=std::shared_ptr
std::shared_ptr
可以隐式转换为
std::shared_ptr
,因此除非使用了错误的编译器,否则在将派生指针传递给使用基指针的函数时应该不会出错

编译精细的示例函数:

class animal{
    public:
        virtual auto print() const -> void = 0;
};

class dog: public animal{
    public:
        auto print() const -> void{ std::cout << "I'm a Dog!\n"; }
};

class cat: public animal{
    public:
        auto print() const -> void{ std::cout << "I'm not a Dog!\n"; }
};

auto func(std::shared_ptr<animal> ptr){
    ptr->print();
}

auto main() -> int{
    auto dog_ptr = std::make_shared<dog>();
    auto cat_ptr = std::make_shared<cat>();
    func(dog_ptr);
    func(cat_ptr);
}

您所说的
返回错误的确切含义是什么?我的第二个问题是
在buffer.add()之前需要向上转换是什么意思
?请参阅我前面的代码示例。@AndyG您的第二条评论也是有效的。我的错误是,我在简单的代码中忘记了从
类动物
继承,因此产生了所有的误解。我仍然不理解向上和向下转换的必要性…@VermillionAzure我解释过:调用buffer.remove()为您提供一个共享的\u ptr,它不能自动强制转换为shahred\u ptr,并且需要使用动态\u指针进行运行时检查\u castNo代码中没有错误。正如我所解释的,它会导致不必要的向下转换。例如,假设您有Dog::print(),这是特定于狗的,而动物没有。您必须动态强制转换从缓冲区获得的结果共享指针才能访问该方法。@narengi正则指针也是如此……是的,正如VermillionAzure所说,正则指针也是如此。我在使用共享\u ptr insta时没有遇到任何问题nces来替换原始指针。您能提供一个共享\u ptr行为不同的示例吗?@VermillionAzure如果有意义,请查看编辑。@narengi-Goo
http://coliru.stacked-crooked.com/a/b2a83c740ed60521

#include <iostream>
#include <memory>

struct A {
  void print() { std::cout << "A" << std::endl; }
};

struct B : public A {
  void print() { std::cout << "B" << std::endl; }
};

void print(std::shared_ptr<A> a) {
    a->print();
}

int main() {
  std::shared_ptr<A> ptr_a(new A);
  std::shared_ptr<B> ptr_b(new B);
  
  ptr_a->print();
  ptr_b->print();
  
  ptr_b->A::print();
  
  //THIS WORKS!
  print(ptr_a);
  print(ptr_b);
}
class animal{
    public:
        virtual auto print() const -> void = 0;
};

class dog: public animal{
    public:
        auto print() const -> void{ std::cout << "I'm a Dog!\n"; }
};

class cat: public animal{
    public:
        auto print() const -> void{ std::cout << "I'm not a Dog!\n"; }
};

auto func(std::shared_ptr<animal> ptr){
    ptr->print();
}

auto main() -> int{
    auto dog_ptr = std::make_shared<dog>();
    auto cat_ptr = std::make_shared<cat>();
    func(dog_ptr);
    func(cat_ptr);
}
I'm a Dog!
I'm not a Dog!