0

我正在玩弄以下使用 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);
}

我尝试做的是设计两个类 (BaseChildBase),其中每个类都有自己的成员Member/ ChildMember。在充分使用ChildBaseobject 及其类型的成员对象之后,ChildMember我将它传递给一个函数,该函数func接收Base并应该使用多态性调用成员的属性。foovar

问题: (1) 在上面的变体中,编译器抱怨:

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

(2) 如果我注释掉 的ChildBase实现get_var,则该函数被视为Base并因此返回一个Member不具有的指针foo2

(3) 我也可以注释掉cb->get_var()->foo2()。整个事情都编译了,但它似乎没有调用ChildMember::foo(),因为没有输出Child Member

有些东西(希望)有点混乱,但我不明白是什么。请各位大神帮忙纠正一下好吗?

编辑1

基于 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 在下面添加了一个答案。

4

5 回答 5

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

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

这是错误的覆盖。n3337 10.3/7

覆盖函数的返回类型应与被覆盖函数的返回类型相同或与函数的类协变。如果函数 D::f 覆盖函数 B::f,则函数的返回类型如果满足以下条件,则它们是协变的:

— 都是类的指针,都是类的左值引用,或者都是类的右值引用

— B::f 的返回类型中的类与 D::f 的返回类型中的类是同一类,或者是 D 的返回类型中的类的明确且可访问的直接或间接基类: :F

— 指针或引用都具有相同的 cv 限定,并且 D::f 的返回类型中的类类型具有与 B::f 的返回类型中的类类型相同或更少的 cv 限定。

在您的情况下,所有条件都失败。您可以使用原始指针或参考,例如http://liveworkspace.org/code/4eQWBI $1 但我认为您应该重写您的界面而不是使用foo2,如果它不是虚拟的。

于 2013-04-01T10:54:25.423 回答
1

要解决您的问题,请查看您的代码的修改和注释版本:

#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);
}
于 2013-04-01T11:04:27.773 回答
1

由于覆盖函数的返回类型不能不同,我将使用动态转换来实现解决方案。因此不需要为 `get_var 和 set_var' 提供虚函数。也不需要 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
}
于 2013-04-01T11:25:48.143 回答
0

shared_ptr不是指针,所以协方差适用。

通常,无论如何,我对协方差的使用持怀疑态度。我通常发现派生类不更改返回类型并在需要返回指向派生函数的指针时提供新函数更简洁。在您的情况下,我会说这是必不可少的,因为您实际上有两个指针(最终可能指向不同的对象)。

于 2013-04-01T11:25:19.220 回答
0

过了一会儿,我虽然下面的代码可能是一个很好的解决方案:

#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);

}

我认为它在没有并行继承或动态转换的情况下实现了我所追求的。它也有超过1级的继承。

输出是:

unique foo in child 1
Child Member 1
Child Member 2
Child-Child Member 2
于 2013-04-01T19:46:48.760 回答