派生类的模板类作为函数的参数 - 危险?

     2023-02-23     130

关键词:

【中文标题】派生类的模板类作为函数的参数 - 危险?【英文标题】:template class of derived class as parameter to function - dangers? 【发布时间】:2019-08-29 00:02:25 【问题描述】:

编辑:澄清一下,我理解为什么这段代码不起作用,我并不是要修复它,而是要理解如果这段代码可以在没有语义错误的情况下编译会有什么危险。强>

我发现以下代码会导致静态语义错误。 我知道这是因为 std::list 是一个模板类,这意味着 std::list<foo*>std::list<bar*> 是不同的类型

我的问题是,如果编译器允许在第二次调用 print_all 时从 std::list<bar*>std::list<foo*> 进行这种类型的转换,会有什么危险?

我在该网站上进行了搜索,但找不到可能发生的坏事的示例。 我也尝试过思考这样的例子,但我不确定这些例子是否正确或准确。 (例如,如果编译器允许这样做,我是否可以将 foo* 对象添加到 print_all() 中的 bar 列表中,因为它已转换为列表?)。

#include <list>
using std::list;
class foo 
    // ...
;
class bar : public foo 
    // ...
;

static void print_all(list<foo*>& L) 
    // ...


list<foo*> LF;
list<bar*> LB;
// ...
print_all(LF); // works fine 
print_all(LB); // static semantic error

【问题讨论】:

【参考方案1】:

list&lt;foo*&gt;list&lt;bar*&gt; 是两个完全不同的类,它们之间没有任何联系,除了从同一个模板std::list (template&lt;class T, class Allocator = std::allocator&lt;T&gt;&gt; class list;) 生成的蜜蜂。因此,它们之间没有转换,除非模板std::list 的作者在TU 的基类时明确编写了std::list&lt;T, A&gt;std::list&lt;U, A&gt; 之间的转换。那不是写的。

实现您想要的一种方法是创建模板函数:

template <class T, class A>
void print_all(std::list<T*, A>& l)

现在,有一些注意事项需要注意:

我看不出你为什么要制作那个静态成员。我会让它成为免费功能,但是我会把它放在一个带有foobar 的命名空间中

如果您想将其使用严格限制为foo 及其派生类,您可以使用sfinae:

template <class T, class A, class E = std::enable_if_t<std::is_base_of_v<foo, T>>>
auto print_all(std::list<T*, A>& l)


最后,您应该考虑将其转换为惯用的 C++ 打印方式,也就是流,并添加 operator&lt;&lt;(std::ostream&amp;, const std::list&lt;T*, A&gt;&amp;)operator&lt;&lt;(std::ostream, const foo&amp;) 以及可能在 foo 上的虚拟打印功能。将它们定义在与 foobar 相同的命名空间中尤为重要。

【讨论】:

首先感谢您的详细回答,但是如果此代码(没有您建议的更改)可以编译,我没有找到答案可能会发生什么坏事? (如果编译器允许第二次调用 print_all)。 @Daniel 正如我所说,这不取决于编译器。这两个类是不同的类,除了从同一个模板生成之外,它们之间没有任何关系。 @Daniel : foobar 之间有继承关系。 std::list&lt;foo&gt;std::list&lt;bar&gt; 之间没有任何关系。 是的,我知道这一点,我是说如果允许这种行为可能会导致什么危险,我很感兴趣。 例如,此代码也不适用于 java 泛型,即使它是不同的机制。【参考方案2】:

您不能使用一个向量代替另一个向量,因为它们是不同的类,但您可以使用转换或复制/移动构造函数和赋值运算符将一个向量隐式或显式转换为另一个向量。它可能会花费您额外的性能(以及复制时的内存)开销,但在您的特定情况下可能是一笔交易。

【讨论】:

如何以派生类的向量为参数实现函数

】如何以派生类的向量为参数实现函数【英文标题】:Howtoimplementfunctionwithvectorofderivedclassesasparameter【发布时间】:2011-05-1600:17:26【问题描述】:(与我之前问过的unansweredquestion有关)。我想实现一个函数,该函数只能以相关类... 查看详情

Cython/Python/C++ - 继承:将派生类作为参数传递给期望基类的函数

】Cython/Python/C++-继承:将派生类作为参数传递给期望基类的函数【英文标题】:Cython/Python/C++-Inheritance:PassingDerivedClassasArgumenttoFunctionexpectingbaseclass【发布时间】:2015-02-1723:51:54【问题描述】:我正在使用Cython来包装一组C++类,允... 查看详情

传递派生模板类的向量

】传递派生模板类的向量【英文标题】:Passingvectorofderived,templatedclass【发布时间】:2015-06-0221:05:41【问题描述】:我想定义一个通用函数foo,它接受数据,可能操作底层类变量,并返回一个int。但是,当我尝试创建一个单独的... 查看详情

将派生类的构造函数声明为父类的友元

】将派生类的构造函数声明为父类的友元【英文标题】:Declareconstructorofaderivedclassasfriendofparentclass【发布时间】:2020-05-1718:08:04【问题描述】:作为每个C++新手,我正在编写自己的矩阵类作为练习。我正在使用这样的类模板:tem... 查看详情

如何键入提示 Python 函数返回从超类派生的任何类的实例?

】如何键入提示Python函数返回从超类派生的任何类的实例?【英文标题】:HowdoItype-hintthataPythonfunctionreturnsinstanceofanyclassderivedfromasuperclass?【发布时间】:2019-04-0215:07:13【问题描述】:我有一堆Django模板包含标记,它们将数据库... 查看详情

《面向对象程序设计》高手进~~~~~~~~~~~~!!

第四章1、有哪几种派生方式?每种方式派生类对其类成员的继承性如何?2、派生类能否直接访问其类的私有成员?若否,应如何实现?3、保护成员有哪些特性,保护成员以公有方式私有方式被继承后的访问特性如何?4、派生... 查看详情

包含指向派生模板类的基类指针的类的赋值运算符和复制构造函数

】包含指向派生模板类的基类指针的类的赋值运算符和复制构造函数【英文标题】:Assignmentoperatorandcopyconstructorforclasscontainingbaseclasspointertoderivedtemplatedclass【发布时间】:2014-09-2308:35:40【问题描述】:为长标题道歉。我正在尝试... 查看详情

将派生对象作为参数传递[关闭]

】将派生对象作为参数传递[关闭]【英文标题】:PassingDerivedObjectsasArgument[closed]【发布时间】:2020-10-2919:13:44【问题描述】:我有一个这样的Student类的构造函数:Student(ISubjectsubject,IStudystudy);ISubject和IStudy是抽象类。然后我创建了... 查看详情

继承和派生

若类B有类A的全部特点,则可将类A作为基类,类B作为派生类,派生类拥有基类的所有成员函数和成员变量,且可以通过对基类进行扩充和修改,但不能对基类的Private成员进行访问。定义:classB:publicA1)类之间的两种关系2)覆盖... 查看详情

派生类的构造函数学习之调用顺序

派生类构造函数的一般格式为:记:B为派生类,A为基类B::B(<构造函数总参数表>):A(<参数表1>),<子对象名>(<参数表2>),......派生类构造函数调用顺序为:基类构造函数、子对象构造函数(如果有)... 查看详情

对派生类的初始化

对派生类的初始化,从派生类的构造函数开始用初始式进行初始化。初始式的格式:派生类的构造函数(参数表):基类构造函数(参数表),对象成员(参数表)...普通成员(初始值)。初始式的存在意义是,1.可以给带参数... 查看详情

给定一个基类作为参数,如果传递了派生类,我如何使用 op<< 重载来打印派生类的特征?

】给定一个基类作为参数,如果传递了派生类,我如何使用op<<重载来打印派生类的特征?【英文标题】:Givenabaseclassasaparameter,howdoIuseop<<overloadtoprintthecharacteristicsofaderivedclassifoneispassed?【发布时间】:2013-03-1317:46:23【问... 查看详情

java示例代码_使用Java反射,如何获取指定构造函数参数的派生类的类的构造函数

java示例代码_使用Java反射,如何获取指定构造函数参数的派生类的类的构造函数 查看详情

基类与派生类的指针和成员函数调用原理

基类与派生类的指针和成员函数调用原理1.如果以一个基础类指针指向一个衍生类对象(派生类对象),那么经由该指针只能访问基础类定义的函数(静态联翩)2.如果以一个衍生类指针指向一个基础类对象,必须先做强制转型动作... 查看详情

unique_ptr 到派生类作为函数的参数,该函数将 unique_ptr 带到基类

】unique_ptr到派生类作为函数的参数,该函数将unique_ptr带到基类【英文标题】:unique_ptrtoaderivedclassasanargumenttoafunctionthattakesaunique_ptrtoabaseclass【发布时间】:2013-07-0216:08:18【问题描述】:我正在尝试在将unique_ptr用于基类的函数中... 查看详情

具有继承的 C++ 类模板

...问题描述】:我正在努力解决一个关于从模板中链接两个派生类的问题。假设我们有一个模板基类Param_B,它将其子类(Param_S或Param_M)之一作为参数。Param_B类的模板参数进一步用于定义其他局部变量(_parent和回调函数_func)。... 查看详情

如何定义派生模板类的功能?(代码片段)

我正在尝试从classFHhashQPwFind定义函数find。你能告诉我我做错了什么吗?我把编辑所说的“这里是错误”放在那里:错误:模板参数数量错误(1,应为2)template<classObject,typenameKeyType>classFHhashQPwFind:publicFHhashQP<Object>public:co... 查看详情

类的继承与派生(代码片段)

第5章类的继承与派生1类的继承与类的派生继承人们追求代码复用(这是提高软件开发效率的重要手段),将继承和派生用于程序设计方法中,从而有了面向对象程序设计的重要特点。C++对代码复用有很强的支持,继承就是支持代... 查看详情