简体   繁体   English

类及其成员的继承和多态性(shared_ptr,C ++ 11)

[英]inheritance and polymorphism for class and its member at the same time (shared_ptr, C++11)

I am playing around with the following structure of classes which use std::shared_ptr (C++11): 我正在研究以下使用std :: shared_ptr(C ++ 11)的类的结构:

#include <string>
#include <iostream>
#include <vector>
#include <memory>

//class Member is given by a 3rd party library, CAN'T modify its structure!
class Member {//no instance of this class allowed
   public:
     Member() {};//should never be called
     virtual ~Member() = 0;//pure virtual distructor;
     virtual void foo() {
       std::cout<<"Member"<<std::endl;
     }
};
Member::~Member() {} //need to define destructor because of child classes 

class ChildMember : public Member {
  public:
     ChildMember() {};
     virtual void foo() {
         std::cout<<"Child Member"<<std::endl;
     }

     virtual void foo2() {
        std::cout<<"unique foo in child"<<std::endl;
     }
};

class Base {
   public:
     Base() {};

   virtual
   std::shared_ptr< Member >
   get_var() {return var;}

   virtual void 
   set_var ( std::shared_ptr< Member > v) { var = v;}

   std::shared_ptr< Member > var;
};


class ChildBase : public Base {
  public:
     ChildBase() {
        //var = std::make_shared<ChildMember>();
     };

  virtual
  std::shared_ptr< ChildMember >
  get_var() {return var;} //(2) : try to comment

  virtual void 
  set_var ( std::shared_ptr< ChildMember > v) { var = v;}

  std::shared_ptr< ChildMember > var;
};

void func(std::shared_ptr<Base> b) {
    b->get_var()->foo();// process input using polymorphism
}

int main() 
{
    std::shared_ptr<ChildBase> cb( std::make_shared<ChildBase>());
    cb->set_var (std::make_shared<ChildMember>() );
    cb->get_var()->foo2();//(3) want to use unique functions of ChildBase;
    cb->var->foo2();      //can access directly as well;
    //cb->var = std::make_shared<ChildMember>();
    func(cb);
}

What i try to do is design two classes ( Base and ChildBase ) where each one has its own member Member / ChildMember . 我试图做的是设计两个类( BaseChildBase ),每个类都有自己的成员Member / ChildMember After full usage of ChildBase object and its member object of type ChildMember , i pass it to a function func which receives Base and should, using polymorphism call the proper foo of a member var . 在充分使用ChildBase对象及其类型为ChildMember成员对象ChildMember ,我将其传递给一个函数func ,该函数接收Base并且应该使用多态性来调用成员var的适当foo

Problems: (1) In the variant in the above, compiler complains that: 问题: (1)在上述变体中,编译器抱怨:

 overriding 'virtual std::shared_ptr<Member> Base::get_var()'
     get_var() {return var;}`

(2) If i comment-out ChildBase implementation of get_var , this function is treated as Base and thus returns a pointer to Member which does not have foo2 . (2)如果我注释掉ChildBase实施get_var ,该功能被视为Base ,从而将指针返回到Member不具有foo2

(3) I can also comment out cb->get_var()->foo2() . (3)我也可以注释掉cb->get_var()->foo2() The whole things compiles, but it seems it does not call ChildMember::foo() as there is no output Child Member ; 整个过程都会编译,但是似乎没有调用ChildMember::foo()因为没有输出Child Member ;

Something is (hopefully) slightly messed up but i don't see what. (希望)有点混乱,但我看不到。 Could you guys please help to correct it? 你们能帮忙改正吗?

EDIT1 : 编辑1

based on Abhijit Kadam answer, the following code fully compiles: 根据Abhijit Kadam的答案,以下代码将完全编译:

#include <string>
#include <iostream>
#include <vector>
#include <memory>

class Member {//no instance of this class allowed
   public:
     Member() {};
     virtual ~Member() = 0;//pure virtual distructor;
     virtual void foo() {
       std::cout<<"Member"<<std::endl;
     }
};
Member::~Member() {} //need to define destructor for child classes 

class ChildMember : public Member {
  public:
     ChildMember() {};
     virtual void foo() {
        std::cout<<"Child Member"<<std::endl;
     }

     void foo2() {
        std::cout<<"unique foo in child"<<std::endl;
     }
};

class Base {
   public:
     Base() {};

     std::shared_ptr< Member >
     get_var() {return var;}

     void set_var ( std::shared_ptr< Member > v) { var = v;}

     std::shared_ptr< Member > var;
};


class ChildBase : public Base {
  public:
     ChildBase() {
       //var = std::make_shared<ChildMember>();
     };  

     std::shared_ptr< ChildMember > var;
};

void func(std::shared_ptr<Base> b) {
    b->get_var()->foo();// process input using polymorphism
}

 void func_vec( std::vector< 
              std::shared_ptr<Base>
           > vec) {
     for (unsigned int i=0;i<vec.size();i++)
          vec[i]->get_var()->foo();
  }

int main() 
{
   std::shared_ptr<ChildBase> cb( std::make_shared<ChildBase>());
   cb->set_var (std::make_shared<ChildMember>() );

   func(cb);

   std::vector< std::shared_ptr<Base>> vec;
   vec.push_back(cb);
   func_vec(vec);

   cb->var->foo2();

   /*std::shared_ptr<ChildMember> ptr(std::dynamic_pointer_cast<ChildMember>(cb->get_var()) );
   if (ptr) {
      ptr->foo2();
   } */
}

EDIT2 added an answer below. EDIT2在下面添加了一个答案。

virtual
std::shared_ptr< Member >
get_var() {return var;}

virtual
std::shared_ptr< ChildMember >
get_var() {return var;} //(2) : try to comment

It's wrong overriding. 这是错误的覆写。 n3337 10.3/7 n3337 10.3 / 7

The return type of an overriding function shall be either identical to the return type of the overridden function or covariant with the classes of the functions. 覆盖函数的返回类型应与覆盖函数的返回类型相同或与函数的类协变。 If a function D::f overrides a function B::f, the return types of the functions are covariant if they satisfy the following criteria: 如果函数D :: f覆盖函数B :: f,则函数的返回类型如果满足以下条件,则它们是协变的:

— both are pointers to classes, both are lvalue references to classes, or both are rvalue references to classes —两者都是指向类的指针,都是对类的左值引用,或者都是对类的右值引用

— the class in the return type of B::f is the same class as the class in the return type of D::f, or is an unambiguous and accessible direct or indirect base class of the class in the return type of D::f —返回类型为B :: f的类与返回类型为D :: f的类相同,或者为返回类型D的类的明确且可访问的直接或间接基类: :F

— both pointers or references have the same cv-qualification and the class type in the return type of D::f has the same cv-qualification as or less cv-qualification than the class type in the return type of B::f. —指针或引用都具有相同的cv限定,并且D :: f的返回类型中的类类型具有与b :: f的返回类型中的类类型相同或更少的cv限定。

All conditions fails in your case. 在您的情况下,所有条件均失败。 You can use raw-pointers, or references for this, something like http://liveworkspace.org/code/4eQWBI $1 But I think you should rewrite your interface and not use foo2 , if it's not virtual. 您可以使用原始指针或对此的引用,例如http://liveworkspace.org/code/4eQWBI $ 1。但是我认为您应该重写您的接口,而不是使用foo2 ,如果它不是虚拟的。

To solve your problem, see this modified and annotated version of your code: 要解决您的问题,请参阅此代码的经过修改和注释的版本:

#include <string>
#include <iostream>
#include <vector>
#include <memory>

class Member {//no instance of this class allowed
public:
    Member() {};
    virtual ~Member() = 0;//pure virtual distructor;
    virtual void foo() {
        std::cout<<"Member"<<std::endl;
    }
};
Member::~Member() {} //need to define destructor for child classes 

class ChildMember : public Member {
public:
    ChildMember() {};
    virtual void foo() {
        std::cout<<"Child Member"<<std::endl;
    }

    virtual void foo2() {
        std::cout<<"unique foo in child"<<std::endl;
    }
};

class Base {
public:
    Base() {};

    // maybe you should have a virtual dtor here
    virtual ~Base();

    // note: NOT virtual
    std::shared_ptr< Member >
    get_var() {return var;}

    // also NOT virtual
    void set_var ( std::shared_ptr< Member > v) { var = v;}

    std::shared_ptr< Member > var;
};


class ChildBase : public Base {
public:
    ChildBase() {
        //var = std::make_shared<ChildMember>();
    };

    // non-virtual version which casts var to the correct type
    std::shared_ptr< ChildMember >
    get_var() {return std::dynamic_pointer_cast<ChildMember>(var);}

    // note: no var here, use the one from Base
};

void func(std::shared_ptr<Base> b) {
    b->get_var()->foo();// process input using polymorphism
}

int main() 
{
    std::shared_ptr<ChildBase> cb( std::make_shared<ChildBase>());
    cb->set_var (std::make_shared<ChildMember>() );
    cb->get_var()->foo2();//(3) want to use unique functions of ChildBase;

    // This can't work:
    //cb->var->foo2();      //can access directly as well;

    //cb->var = std::make_shared<ChildMember>();
    func(cb);
}

As the return types of overriding functions cannot differ I would have use dynamic cast to implement the solution. 由于覆盖函数的返回类型不能不同,因此我将使用动态强制转换来实现该解决方案。 Hence no need to have virtual functions for `get_var and set_var'. 因此,不需要为get_var和set_var使用虚函数。 Also no need for foo2 to be virtual unless the class would be further derived by some other class. 同样也不需要foo2是虚拟的,除非该类可以被其他类进一步派生。

int main() 
{
    std::shared_ptr<ChildBase> cb( std::make_shared<ChildBase>());
    cb->set_var (std::make_shared<ChildMember>() );

    shared_ptr<ChildMember> ptr(dynamic_pointer_cast<ChildMember>(cb->get_var()) );
    if (ptr) {
        ptr->foo2();
    } 
}

class Member {//no instance of this class allowed
   public:
     Member() {};
     virtual ~Member() = 0;//pure virtual distructor;
     virtual void foo() {
       std::cout<<"Member"<<std::endl;
     }
};
Member::~Member() {} //need to define destructor for child classes 

class ChildMember : public Member {
  public:
     ChildMember() {};
     virtual void foo() {
         std::cout<<"Child Member"<<std::endl;
     }

     void foo2() {
        std::cout<<"unique foo in child"<<std::endl;
     }
};

class Base {
   public:
     Base() {};

   std::shared_ptr< Member >
   get_var() {return var;}

   void set_var ( std::shared_ptr< Member > v) { var = v;}

   std::shared_ptr< Member > var;
};


class ChildBase : public Base {
  public:
     ChildBase() {
        //var = std::make_shared<ChildMember>();
     };  

  std::shared_ptr< ChildMember > var;
};

void func(std::shared_ptr<Base> b) {
    b->get_var()->foo();// process input using polymorphism
}

shared_ptr is not a pointer, so covariance doesn't apply. shared_ptr 不是指针,因此协方差不适用。

Typically, I'm sceptical about the use of covariance anyway. 通常,我总是对协方差的使用持怀疑态度。 I generally find it cleaner for the derived class to not change the return types, and to provide a new function if it needs to return a pointer to a derived function. 对于派生类,我通常会发现它更干净,不会更改返回类型,并且如果需要返回指向派生函数的指针,则可以提供一个新函数。 In your case, I'd say that this is essential, since you actually have two pointers (which could end up pointing to different objects). 对于您的情况,我想说这是必不可少的,因为您实际上有两个指针(最终可能指向不同的对象)。

after a while, i though the following code might be a good solution: 过了一会儿,我虽然以下代码可能是一个很好的解决方案:

#include <string>
#include <iostream>
#include <vector>
#include <memory>

class Member {//no instance of this class allowed
   public:
     Member() {};
     virtual ~Member() = 0;//pure virtual distructor;
     virtual void foo() {
       std::cout<<"Member"<<std::endl;
     }
};
Member::~Member() {} //need to define destructor for child classes 

class ChildMember1 : public Member {
  public:
     ChildMember1() {};
     virtual void foo() {
        std::cout<<"Child Member 1"<<std::endl;
     }

     void foo1() {
        std::cout<<"unique foo in child 1"<<std::endl;
     }
};

class ChildMember2 : public Member {
  public:
     ChildMember2() {};
     virtual void foo() {
        std::cout<<"Child Member 2"<<std::endl;
     }
};

class ChildChildMember2 : public ChildMember2 {
   public:
      ChildChildMember2() {};
      virtual void foo() {
         std::cout<<"Child-Child Member 2"<<std::endl;
      }
};

class Base {
   public:
     Base() {};
     virtual
     ~Base() {};

     virtual
     std::shared_ptr< Member >
     get_var() = 0; //purely abstract class

};

class ChildBase1 : public Base {
  public:
     ChildBase1() {
       var = std::make_shared<ChildMember1>();
     };

     virtual
     std::shared_ptr< Member >
     get_var() {return var;}

     std::shared_ptr< ChildMember1 > var;
};

class ChildChildBase : public ChildBase1 {
   public:
      ChildChildBase() {
         var2 = std::make_shared< ChildChildMember2>();
      }

   virtual
   std::shared_ptr< Member >
   get_var() { return var2; }

   std::shared_ptr< ChildChildMember2 > var2;
};


class ChildBase2 : public Base {
  public:
     ChildBase2() {
       var = std::make_shared<ChildMember2>();
     };  

     virtual
     std::shared_ptr< Member >
     get_var() {return var;}

     std::shared_ptr< ChildMember2 > var;
};

void func(std::shared_ptr<Base> b) {
    b->get_var()->foo();// process input using polymorphism
}

int main() 
{
   std::shared_ptr<ChildBase1> cb1( std::make_shared<ChildBase1>());
   cb1->var->foo1();
   func(cb1);

   std::shared_ptr<ChildBase2> cb2( std::make_shared<ChildBase2>());
   func(cb2);

   std::shared_ptr<ChildChildBase> ccb( std::make_shared<ChildChildBase>());
   func(ccb);

}

I think it achieves what i was after without parallel inheritance or dynamic casting. 我认为它可以实现我所追求的,而无需并行继承或动态转换。 It also has more than 1 lvl of inheritance. 它还具有1个以上的继承。

The output is: 输出为:

unique foo in child 1
Child Member 1
Child Member 2
Child-Child Member 2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM