覆盖派生 class 中的模板基方法?
overriding the template base method in derived class?
假设我有一个基 class 如下:
template <typename T>
class Base {
// implementation
void do_something() { /* ... */ } ;
};
然后,我创建一个 Derived
class 如下,并重写 do_something()
方法:
template <typename T>
class Derived : public Base<T> {
// implementation
void do_something() { /* ... */ } ;
};
我知道虚拟化在 class 模板中不起作用,我只是隐藏了方法的实现。但我确实想将一堆派生 classes 和基础 classes 存储到一个向量中,(我不想使用类型擦除或多态性),
我的问题是,假设 static_cast
of Derived
class to base class 给我 do_something
of based class,有什么方法可以将它们存储为基础 classes 而每个都有 do_something()
class 的实现?
but I do want to store a bunch of derived classes and base classes into a vector, (I do not want to use type erasure, or polymorphism),
这在 C++ 中已经不可能了。在 C++ 中,向量只能包含相同静态类型的对象。 vector 可以包含不同类型对象的唯一方法是,如果它们的静态类型仍然相同,但它们具有不同的动态类型,但这是您说过不想使用的类型 erasure/polymorphism。
我认为您可能需要重新考虑您的要求,因为您的问题本质上是:我想做某事,但我不想使用明确定义为做某事的唯一方法的技术 X在 C++ 中!
我这样做了,它似乎工作正常:
#include <iostream>
template <typename T>
struct Base {
virtual void do_something() { std::cout << "Base::do_something()\n"; }
};
template <typename T>
struct Derived : public Base<T> {
virtual void do_something() { std::cout << "Derived::do_something()\n"; }
};
int main() {
Base<int> b;
Derived<int> d;
Base<int> *p;
p = &b;
p->do_something();
p = &d;
p->do_something();
return 0;
}
输出:
Base::do_something()
Derived::do_something()
melpomene 的答案有一点变化(为 Base<T>
结构添加一个无模板基结构,BaseOfBase
)允许使用不同派生类基的公共向量T
种类型。
一个工作示例
#include <vector>
#include <iostream>
struct BaseOfBase
{ virtual void do_something () = 0; };
template <typename T>
struct Base : public BaseOfBase
{
T val;
void do_something ()
{ std::cout << "Base::do_something() [" << val << "]\n"; };
};
template <typename T>
struct Derived : public Base<T>
{ void do_something()
{ std::cout << "Derived::do_something() [" << this->val << "]\n"; } };
int main ()
{
std::vector<BaseOfBase*> vpbb;
Base<int> bi;
Derived<int> di;
Base<std::string> bs;
Derived<std::string> ds;
bi.val = 1;
di.val = 2;
bs.val = "foo";
ds.val = "bar";
vpbb.push_back(&bi);
vpbb.push_back(&di);
vpbb.push_back(&bs);
vpbb.push_back(&ds);
for ( auto const & pbb : vpbb )
pbb->do_something();
}
当我们说虚拟化在模板 classes 中不起作用时,我们并不是说您不能在模板中执行虚函数 class,也不意味着您不能用它的专门版本覆盖成员函数。
@melpomene 展示了一个一般覆盖的例子,我将在这里展示专业化:
#include <iostream>
template <typename T>
class Base {
public:
virtual T do_something(T in) { std::cout << "Base::do_something()\n"; return in; }
};
class Derived : public Base<int> {
public:
virtual int do_something(int in) { std::cout << "Derived::do_something()\n"; return in - 1; }
};
void main()
{
Base<int> b;
Derived d;
Base<int> *p = &b;
auto r1 = p->do_something(10);
std::cout << r1 <<std::endl;
p = &d;
auto r2 = p->do_something(10);
std::cout << r2 << std::endl;
}
哪个会输出
Base::do_something()
10
Derived::do_something()
9
表明它完全按预期工作。
我们说
的意思
virtualization does not work in class templates
基本上意味着您不能将派生的 class 用作模板,而该基数是预期的。
考虑上面的classes Base<T>
和Derived
,那么如果我们有如下代码:
#include <memory>
template <typename T>
void Test(std::unique_ptr<Base<T>> in){ std::cout << "This will not work with derived"; }
void main()
{
Base<int> b;
Derived d;
auto ptr = std::unique_ptr<Derived>(&d);
Test(ptr); // <-- Will fail to compile as an invalid argument
}
它会失败,因为 std::unique_ptr<Derived>
没有继承自 std::unique_ptr<Base<T>>
,尽管 Derived
本身继承自 Base<T>
。
假设我有一个基 class 如下:
template <typename T>
class Base {
// implementation
void do_something() { /* ... */ } ;
};
然后,我创建一个 Derived
class 如下,并重写 do_something()
方法:
template <typename T>
class Derived : public Base<T> {
// implementation
void do_something() { /* ... */ } ;
};
我知道虚拟化在 class 模板中不起作用,我只是隐藏了方法的实现。但我确实想将一堆派生 classes 和基础 classes 存储到一个向量中,(我不想使用类型擦除或多态性),
我的问题是,假设 static_cast
of Derived
class to base class 给我 do_something
of based class,有什么方法可以将它们存储为基础 classes 而每个都有 do_something()
class 的实现?
but I do want to store a bunch of derived classes and base classes into a vector, (I do not want to use type erasure, or polymorphism),
这在 C++ 中已经不可能了。在 C++ 中,向量只能包含相同静态类型的对象。 vector 可以包含不同类型对象的唯一方法是,如果它们的静态类型仍然相同,但它们具有不同的动态类型,但这是您说过不想使用的类型 erasure/polymorphism。
我认为您可能需要重新考虑您的要求,因为您的问题本质上是:我想做某事,但我不想使用明确定义为做某事的唯一方法的技术 X在 C++ 中!
我这样做了,它似乎工作正常:
#include <iostream>
template <typename T>
struct Base {
virtual void do_something() { std::cout << "Base::do_something()\n"; }
};
template <typename T>
struct Derived : public Base<T> {
virtual void do_something() { std::cout << "Derived::do_something()\n"; }
};
int main() {
Base<int> b;
Derived<int> d;
Base<int> *p;
p = &b;
p->do_something();
p = &d;
p->do_something();
return 0;
}
输出:
Base::do_something()
Derived::do_something()
melpomene 的答案有一点变化(为 Base<T>
结构添加一个无模板基结构,BaseOfBase
)允许使用不同派生类基的公共向量T
种类型。
一个工作示例
#include <vector>
#include <iostream>
struct BaseOfBase
{ virtual void do_something () = 0; };
template <typename T>
struct Base : public BaseOfBase
{
T val;
void do_something ()
{ std::cout << "Base::do_something() [" << val << "]\n"; };
};
template <typename T>
struct Derived : public Base<T>
{ void do_something()
{ std::cout << "Derived::do_something() [" << this->val << "]\n"; } };
int main ()
{
std::vector<BaseOfBase*> vpbb;
Base<int> bi;
Derived<int> di;
Base<std::string> bs;
Derived<std::string> ds;
bi.val = 1;
di.val = 2;
bs.val = "foo";
ds.val = "bar";
vpbb.push_back(&bi);
vpbb.push_back(&di);
vpbb.push_back(&bs);
vpbb.push_back(&ds);
for ( auto const & pbb : vpbb )
pbb->do_something();
}
当我们说虚拟化在模板 classes 中不起作用时,我们并不是说您不能在模板中执行虚函数 class,也不意味着您不能用它的专门版本覆盖成员函数。
@melpomene 展示了一个一般覆盖的例子,我将在这里展示专业化:
#include <iostream>
template <typename T>
class Base {
public:
virtual T do_something(T in) { std::cout << "Base::do_something()\n"; return in; }
};
class Derived : public Base<int> {
public:
virtual int do_something(int in) { std::cout << "Derived::do_something()\n"; return in - 1; }
};
void main()
{
Base<int> b;
Derived d;
Base<int> *p = &b;
auto r1 = p->do_something(10);
std::cout << r1 <<std::endl;
p = &d;
auto r2 = p->do_something(10);
std::cout << r2 << std::endl;
}
哪个会输出
Base::do_something()
10
Derived::do_something()
9
表明它完全按预期工作。
我们说
的意思virtualization does not work in class templates
基本上意味着您不能将派生的 class 用作模板,而该基数是预期的。
考虑上面的classes Base<T>
和Derived
,那么如果我们有如下代码:
#include <memory>
template <typename T>
void Test(std::unique_ptr<Base<T>> in){ std::cout << "This will not work with derived"; }
void main()
{
Base<int> b;
Derived d;
auto ptr = std::unique_ptr<Derived>(&d);
Test(ptr); // <-- Will fail to compile as an invalid argument
}
它会失败,因为 std::unique_ptr<Derived>
没有继承自 std::unique_ptr<Base<T>>
,尽管 Derived
本身继承自 Base<T>
。