如果我们有一个基*类,如何访问派生模板类的成员函数
How to access member funtions of a derived Template class if we have a base* class
我有一个从基类派生的模板类。
同样在main中,我有一个vector
容器,其中包含各种类型的派生类。不知道Derived
类的类型,我怎么能 在 Main 中访问其成员函数?
模板专用化可能是解决此问题的好方法。但是,我该怎么做呢?
class Base{ // The base class of a template class
public:
Base(){}
virtual ~Base(){}
};
template <typename T>
class Derived : public Base{ // The template class,
// derived from the base class.
T data;
public:
Derived(){}
~Derived(){}
T get() { return data; }
void set( T val) { data = val; }
};
int main() {
vector <Base*> myObject;
// I have different types of Derived class
// in a vector conteiner.
Derived<int> *D1=new Derived<int>;
Derived<float>*D2=new Derived<float>;
Derived<char> *D3=new Derived<char>;
myObject.push_back(D1);
myObject.push_back(D2);
myObject.push_back(D3);
for (int i=0;i<myObject.size();i++){
// myObject[i]->set(4); Error! : myObject is a vector of <Base*>
// myObject[i]->get(); Error! : not a vector of <Derived*>
}
return 0;
}
您将无法使用非模板基类执行所需的操作。 您尝试做的是通过存储指向非模板基类的指针来擦除模板派生类的类型。 这称为类型擦除 - https://en.wikipedia.org/wiki/Type_erasure
可以dynamic_cast
,然后打开派生类的类型。 例如
for (int i=0;i<myObject.size();i++){
if (auto* ptr = dynamic_cast<Derived<int>*>(myObject[i])) {
ptr->set(4);
ptr->get();
} else if (auto* ptr = dynamic_cast<Derived<double>*>(myObject[i])) {
ptr->set(1.0);
ptr->get();
}
}
您可能会对std::any
如何解决此接口问题感兴趣。 看看这里 http://en.cppreference.com/w/cpp/utility/any/any_cast
另一种方法是不投资类型擦除并使用std::variant
。
您想要的确切行为无法通过 c++ 的标准方法实现。此设计不是多态的,并且对象中没有任何类型信息。此外,您的对象似乎也没有通用接口(在 c++ 上下文中(,因为所有函数都以不同的类型运行。
这似乎是 Variant 类型的实现,您希望在一个容器中存储不同的值(整数、字符串、浮点数等(。
解决此问题的最简单方法是将type
文件添加到基类,并为派生类中的每个类型为其分配特定值。但是,您应该手动检查它,并在每次要访问实际值时转换为所需的实际时间。
enum ValueType
{
Bool, Int, Float
};
class Base
{
protected:
ValueType _type;
public:
ValueType type() const { return _type; }
};
// usage example
Base *val = vector[something];
switch (val->type()) {
case Int: { int intvalue = Derived<int>(val)->get(); }
}
另一种方法是通过让它们返回/接受一些可以表示任何类型的值的通用类型(如字符串(来为get
/set
创建通用接口,并像往常一样在没有模板的情况下使用继承和虚函数。此实现的缺点是字符串处理和存储的成本。
class Base
{
public:
virtual string get() const = 0;
virtual void set(const string &newval) = 0;
};
class IntValue : public Base
{
public:
/* imagine we have that magic IntToStr function */
string get() const override { return IntToStr(_value); }
private:
int _value;
};
我相信最有效的方法是将所有可能的 getter 和 setter 放在基类中,并将它们覆盖到特定的派生类中。有了这个,您可以获得统一的界面,并且可以进行额外的方便的值转换(例如将 int 读取为 char 或 bool 或字符串(。
class Base
{
public:
virtual bool getBool() const = 0;
virtual int getInt() const = 0;
// etc for other types getters and setters
};
class IntValue
{
public:
bool getBool() const override { return _value != 0; }
int getInt() const override { return _value; }
// for incompatible types - throw error or return default value
};
还有另一种方法可以使其尽可能快,但也尽可能丑陋,那就是让模板化的 get/set 版本及其实现(没有虚拟(专门针对每种类型和每种可能的变体类型。有了这个,您必须保留内部type
变量,该变量将保存实际值类型。在这种情况下,您根本不需要继承。
问题在于实现类型的方式。当您声明std::vector<Base*>
时,C++准备存储能够Base
功能的对象,仅此而已。当您将这三个对象放入矢量中时,C++会忘记它们的基础类型。所以当你调用myObject[i]->set(4)
时,系统不可能知道该呼叫哪个set
。
通常,解决方案是在基类中创建虚拟方法。但是,正如您提到的,您无法这样做,因为您在get
和set
中具有模板类型。下一个想法是实现一个模板化的基类并Derived<T>
子类Base<T>
。这将解决问题,但它会创建一个新问题:你不能有一个异构对象的向量。
所以我认为从根本上说,你需要考虑你想做什么。这里有一些问题要问自己。
您是否预先知道要存储多少对象以及将存储哪些对象?如果在编译时知道对象的数量和类型,请考虑
Derived
对象的std::tuple
。既然您将所有对象都设置为整数
4
,您是否知道所有对象类型都可以转换为整数/从整数转换?如果是这样,您可以将get_int
和set_int
编写为基类中的虚函数,并调用它们可以委托给子类中的get
和set
。如果您不知道预先需要多少对象,但您知道它们都来自一组有限的对象,请考虑
std::vector
std::variant
(或boost::variant
,如果您无法访问 C++17(。如果你真的需要所有的通用性,你可以使用
std::any
来规避类型系统(或者,如果你没有C++17,也可以再次boost::any
(。但要认真考虑一下你是否能做得更好。上述解决方案将为您提供更好的类型安全性,并使您的代码不易出错。
- 如何使用单独文件中的派生类访问友元函数对象
- 为什么此派生对象无法访问基类的后递减方法?
- C++:为什么无法在派生类中访问受保护的构造函数?
- 如何使用 C++ 中的继承函数访问派生类中的局部变量
- 派生的 wxPanel 控件如何访问其中包含 wxDialog 中的数据?
- 从纯虚拟类 (A) 派生的指针无法访问来自纯类 (B) 的重载方法
- C ++基础私有方法在将自身转换为派生类后可以访问吗?
- 按基类对象访问派生类资源时出错
- 使(虚拟)函数在大多数派生类中无法访问中间基类中可访问,定义良好?
- 从模板化父类中的派生内部类访问受保护的成员变量
- 如何从派生类访问基类中的重载运算符?
- 两个抽象类,派生自同一个基类.如何访问从一个抽象类到另一个抽象类的指针
- C++11: 如何访问派生类中的基类成员?
- 访问派生类的 QMetaObject
- 使用基类对象访问派生的仅类方法
- 如何在 c++ 中通过基类引用访问派生类的对象?
- 派生类无法访问基类的受保护成员
- 如何在 c++ 中使用多态性访问派生类字段?
- 为了访问方法,从基类动态转换为派生类
- C++继承从基类指针访问派生类中的非虚拟函数