【问题标题】:Accessing object data/method members with templates使用模板访问对象数据/方法成员
【发布时间】:2013-11-18 01:10:37
【问题描述】:

假设我实现了自己的链表,并且它的节点可以包含“汽车”类型的元素。

在这个实现中,我有一个方法PrintList(),它有一个循环并为每个节点调用toString 方法。

我的班级是什么样的供参考:

template<class T>
class ArrayList {
private:
   class Node {
   private:
   // Node accessors
   T* element;
   public:
   // ctor's
   //Accessors etc
   void GetElement();
   string toString();
   };
   //members
   int size;
   // etc


public:
   void PrintList();
};

节点的toString() 看起来像这样:

string myNode::toString() {
   // Returns a Car pointer.
   // Still in myList implementation
   // For a generic version I'ld want 'getEleemnt' or something.
   return this->GetCar()->toString();


}


Car* Mylist::Node::GetCar() {
   //Returns a car* ptr
   return this->myCar;
   //car has an implementation of toString() which is soon invoked.
}


//Inside my Car class written in some other cpp file, has no relationship
//with MyList.
string Car()::toString() {
   //Car type is a set of enums defined in a header.
   //Car has a EnumeratedType member field.
   switch ( this->getEnumeratedType ) {
   case 0:
    return "I'm a veyron"
    // etc

   }

}

假设我现在实现了我自己的链接列表模板。 (因为作为一名学生,我觉得这个练习很有趣,也是练习我的 C++ 的好机会)。上面的 toPrint() 恶作剧不起作用。

template <class T>
string MyList<T>::myNode::toString() {
   // Returns a T* pointer.
   // now in generic <T> myList implementation
   // 
   return this->GetElement()->toString(); // this does not compile....


}

template <class T>
T* Mylist<T>::Node::GetElement() {
   //Returns a element* ptr?
   return this->myElement;
   // This compiles iirc.
}

似乎没有办法在未知的类模板上调用方法。 Car 与 myList 没有关系,我可能有兴趣存储与 Car 无关的任何对象,假设我想存储花,即使它们都有 toString 实现,编译器也不让我调用它们。

一个可能的建议是创建一个 IPrintable 接口,我打算让通用列表使用的任何对象都继承自该接口,但我不知道这是否真的解决了我的问题。

总而言之,我正在返回一个指针,类型为“T”,它可能是 Car,也可能是 Flowers,我想知道是否有某种方法可以盲目地抛出 toString() 飞镖并让他们调用他们的实现.

【问题讨论】:

  • 什么叫通用列表?起初,您似乎只是指像std::list 这样的模板化列表,后来看起来更像是指包含void*s 或其他内容的列表。
  • 我自己实现的通用列表?你说的两个例子都不是我做的,所以我不知道如何回答。
  • 我觉得改写得更容易理解。
  • 注意,这些不是不是泛型,它们是模板。它们是不同的,即使它们看起来相同。
  • 因为我是学生,我认为它对练习指针很有指导意义?我有考试,这类事情有助于为考试做准备。即使最后的课程是“感谢上帝的图书馆”,也并非完全缺乏实践价值。

标签: c++ list templates


【解决方案1】:

您似乎已经实现了自己的列表类,所以我无法对此发表评论。但是让我通过使用常规的 stl 容器来解释它。当您拥有特定类型的容器时:

std::vector<Car> cars;

你可以只输入那个类型: 汽车.push_back(汽车()); 汽车.push_back(用户()); // 错误

如果您使用多态性,您可以在使用指针时将不同类型的对象(继承自同一个基类)存储在容器内:

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

class Car {
public:
    virtual ~Car() {}
    virtual std::string toString() const {
        return "I'm a car";
    }
};

class RaceCar : public Car {
public:
    virtual std::string toString() const {
        return "I'm a race car";
    }
    void raceCarSpecificMethod() const { }
};

int main() {
    typedef std::shared_ptr<Car> CarPtr;
    std::vector<CarPtr> cars;
    cars.emplace_back(std::make_shared<Car>());
    cars.emplace_back(std::make_shared<RaceCar>());
    for (const auto &car : cars) {
        std::cout << car->toString() << std::endl;
    }
    return 0;
}

但是,您不能以这种方式调用诸如“raceCarSpecificMethod()”之类的方法。如果要调用该方法,则必须将 for 循环更改为:

for (auto &car : cars) {
    std::cout << car->toString() << std::endl;
    std::shared_ptr<RaceCar> race_car = std::dynamic_pointer_cast<RaceCar>(car);
    if (race_car) {
        race_car->raceCarSpecificMethod();
    }
}

dynamic_pointer_cast 将 Car 指针转换为 RaceCar 指针,使您可以使用 raceCarSpecificMethod。您必须检查返回的指针是否为 nullptr。如果转换的指针不是 RaceCar 指针,则将返回 nullptr。如果上面的例子我使用了shared_ptrs,那么在使用常规指针时你应该使用:

RaceCar *race_car = dynamic_cast<RaceCar*>(car); // assuming that car is a Car*

我不确定您为什么要编写自己的列表类,但总的来说,我建议您坚持使用 std::vector。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-26
    • 2018-09-18
    相关资源
    最近更新 更多