【问题标题】:C++ member access from a derived class of a templated type从模板类型的派生类访问 C++ 成员
【发布时间】:2017-11-27 17:32:32
【问题描述】:

长话短说,我在这里想要的是在基类中声明一个模板类型并能够访问该类型 A<T> 以便基类 B 包含它并且派生类 C 能够以C::A<T> 访问它。我确实尝试在class B 中声明一个int,并且可以从派生的C 类中访问C::int,这是错误!

||In constructor ‘D::D()’:|
|74|error: no match for ‘operator=’ (operand types are ‘A<C*>’ and ‘A<B*>’)|
|4|note: candidate: A<C*>& A<C*>::operator=(const A<C*>&)|
|4|note:   no known conversion for argument 1 from ‘A<B*>’ to ‘const A<C*>&’|

这是编译的代码(注释A&lt;B*&gt; i; 并取消注释A&lt;C*&gt; i; 以获取错误)。

#include <iostream>
//class with a template parameter
template <class a>
class A
{
    private:

        int somevalue;

    public:

    A(){}
    ~A(){}
    void print()
    {
        std::cout<<somevalue<<std::endl;
    }
};

//1. could forward declare
class C;
class B
{
    protected:

        A<B*> i;
        //2. and then use
        //A<C*> i;

    public:

        B(){}
        ~B(){}
        A<B*> get()
        {
            return i;
        }

        /*
        //3. use this return instead
        A<C*> get()
        {
            return i;
        }
        */
};
//specialization of B that uses B's methods variables
class C : public B
{
    protected:

    public:

        C(){}
        virtual ~C(){}
        void method()
        {
            B::i.print();
        }
};
//class D that inherits the specialization of C
class D : public C
{
    private:

        A<B*> i;//works
        //4. but I want the inherited type to work like
        //A<C*> i;// so that the type C* is interpreted as B*

    public:

    D()
    {
        this->i = C::i;
    }
    ~D(){}
};
///////////////////////////////////////////////////////////////////////
int main()
{
    D* d = new D();

    delete d;

    return 0;
}

【问题讨论】:

  • "这将解决整个问题,但它不是可移植的,也不像 C++。"解释一下?
  • 我不想在每次使用该类时都声明该类名。考虑到我希望在不知道其内容的情况下将头文件存储在某处。
  • 这是 MyTemplate 和 MyTemplate 类型长期以来的最爱,与继承问题无关吗?我实际上无法理解你的问题。它非常冗长且杂乱无章,您的示例中的代码比您需要的要多。
  • 很抱歉,我实际上并不了解您的目标是什么,所以我无法告诉您如何更改代码以适应它。我可以告诉你,你不需要这种行为来实现你的目标......但根据上面的例子,我不知道哪种选择最适合你。我似乎也找不到骗子,虽然我知道我过去见过很多次。
  • @pandoragami 不,不是。 A 是您在代码中创建的类模板(“这就是我的全部!”)。如果您有其他一些实际代码,则需要发布。

标签: c++ templates inheritance derived-class


【解决方案1】:

但是如果我们尝试这个std::list&lt;template parameter&gt; LIST 然后插入它会怎样?这就是问题A&lt;T&gt;std::list

据我了解您现在的问题,您似乎有一个std::list&lt;Base *&gt;(为了清楚起见,将B 重命名为Base)并想填写一个std::list&lt;Concrete*&gt;(重命名为CConcrete,它是源自Base)。

为此,您需要遍历Base* 指针,检查每个指针是否可以向下转换Concrete*,如果可以,将其添加到std::list&lt;Concrete*&gt;。你也需要考虑一下如果向下转型失败了怎么办。

要使所有这些工作,您的Base 需要是一个多态基类,即它必须包含一个虚拟成员函数(不要忘记将析构函数设为虚拟)。另请注意,就管理这些指针的所有权而言,这听起来像是一场等待发生的灾难。

template<typename Base, typename Concrete>
std::list<Concrete*> downcast_list (std::list<Base*> const & bases) {
 std::list<Concrete*> result;
  for (auto const base_ptr : bases) {
    Concrete * concrete_ptr = dynamic_cast<Concrete*>(base_ptr);
    if (concrete_ptr != nullptr) {
      result.push_back(concrete_ptr);
    } else {
      // Error or ignore?
    }
  }
  return result;
}

注意:更惯用的版本将使用迭代器。

【讨论】:

    【解决方案2】:

    我找到了我的问题的模式,它实际上非常简单,它作为封装类类型 a 的基础(这是要传递的模板参数,请尝试将我的问题作为对 @ 的参考987654323@)。图案如下图所示,一般是我想要的。我在这个网页上找到了它Using Inheritance Between Templates chapter 7.5 from the book entitled OBJECT-ORIENTED SOFTWARE DESIGN and CONSTRUCTION with C++ by Dennis Kafura。我会将其复制到编辑后的代码下方,以备将来参考,以防其他人需要它。

    template <class a> 
    class B 
    {
        private:      
    
        public:
    
            B();     
            ~B();
    };
    
    template <class a> 
    class C : public B<a>
    {
       public:
        C();
        ~C();
    };
    

    这是改编自它的代码。

    template <class QueueItem> class Queue 
    {
       private:
    
          QueueItem buffer[100];
          int head, tail, count;
    
        public:
                    Queue();
          void      Insert(QueueItem item);
          QueueItem Remove();
                   ~Queue();
    };
    
    template <class QueueItem> class InspectableQueue : public Queue<QueueItem>
    {
       public:
                   InspectableQueue();
         QueueItem Inspect();  // return without removing the first element
                  ~InspectableQueue();
    };
    

    【讨论】:

      【解决方案3】:

      尝试改变这个:

      #include <iostream>
      //class with a template parameter
      template <class a>
      class A {
      private:    
          int somevalue;    
      public:    
          A(){}
          ~A(){}
          void print() {
              std::cout<<somevalue<<std::endl;
          }
      };
      

      //1. could forward declare
      class C;
      class B {
      protected:    
          A<B*> i;
          //2. and then use
          //A<C*> i;    
      public:    
          B(){}
          ~B(){}
          A<B*> get() {
              return i;
          }
      
          /*/3. use this return instead
          A<C*> get() {
             return i;
          } */
      };
      

      //specialization of B that uses B's methods variables
      class C : public B {
      protected:
      public:    
          C(){}
          virtual ~C(){}
          void method() {
              B::i.print();
          }
      };    
      

      //class D that inherits the specialization of C
      class D : public C {
      private:   
          A<B*> i;//works
          //4. but I want the inherited type to work like
          //A<C*> i;// so that the type C* is interpreted as B*
      public:    
          D() {
              this->i = C::i;
          }
          ~D(){}
      };
      

         int main() {
          D* d = new D();    
          delete d;    
          return 0;
      }
      

      到这样的事情:

      #include <iostream>
      
      //class with a template parameter
      template <typename T>
      class Foo {
      private:    
          T value_;    
      public:    
          Foo(){} // Default
          Foo( T value ) : value_(value) {}
          ~Foo(){}
          void print() {
              std::cout<< value_ << std::endl;
          }
      };
      

      class Derived;
      class Base {
      protected:
          Foo<Base*> foo_;
          Base(){} // Default;
          virtual ~Base(){}
      
          // Overload This Function
          template<typename T = Base>
          /*virtual*/ Foo<T*> get();
      
          /*virtual*/ Foo<Base*> get() { return this->foo_; }
          /*virtual*/ Foo<Derived*> get();
      };
      

      class Derived : Base {
      public:
          Derived() {}
          virtual ~Derived() {}
      
          void func() {
              Base::foo_.print();
          }
          void Foo<Derived*> get() override { return this->foo_; } 
       };
      

      这就是我试图回答你的问题的最大程度......

      • 有些对象没有在您的代码中使用
      • 有些方法没有被调用。
      • 很难理解方向/间接 您对继承树的意义。
      • 您是从没有virtual destructorbase 类继承的
      • 可能还有其他一些我现在无法想到的事情。

      我非常愿意尝试帮助您;但这是我目前所展示的内容。

      编辑 -- 我对 base &amp; derived 类进行了更改,并删除了重载函数模板声明中的 virtual 关键字 - 属于这些类的定义。

      【讨论】:

      • @pandoragami 没问题;我是自学成才的,从未接受过任何正式培训或任何大学课程,从未有人坐在那里教我一切。我必须找到我能得到的几本书,我不得不阅读一堆平凡而古老的网站,这些网站可以追溯到 90 年代中后期,即使ftp 网站仍然被广泛使用。为了让简单的事情发挥作用,我不得不进行大量的试验和错误以及许多失败。然后花时间学习语言;我目前仍在学习。有时帮助别人可以帮助我学习,因为我必须停下来思考一下。
      • 抱歉,您的代码不起作用,您不能同时使用虚拟和模板。
      • 哦;是的...我自己还在学习模板,它们是 C++ 语言中较难掌握的部分之一。是的,您可以将析构函数保留为虚拟,并将任何非模板方法或函数保留为虚拟,但对于属于该类的任何重载模板函数;虚拟存储不起作用。
      • 我在我的问题中添加了我的答案,它解决了(不完全是)我的问题,并且不需要任何过于复杂的东西。似乎没有真正简单的方法来继承具有模板参数的数据类型,并且无论如何都必须在派生类中定义(专门化)它。我的解决方案仅将数据类型封装为模板参数,因此它被传递了!有总比没有好,这是使用简单的 C++ 编码可以获得的最佳效果。
      猜你喜欢
      • 2021-07-25
      • 1970-01-01
      • 2018-09-18
      相关资源
      最近更新 更多