为啥virtual clone(),返回智能指针,不能covariance?

DoorWay
DoorWay 05月07日 字数 160

virtual unique_ptr<Child> Child::Clone() override;

最近有这种需求,子类提供克隆方法,返回自身类型的智能指针,不行。必须返回基类的智能指针?

这种一般怎么设计解决?

59 个回复
z16166
Netguy 05月07日

virtual肯定不行。用模板?

fanci
大葡萄 05月08日

没啥好办法,返回基类的吧

【 在 DoorWay () 的大作中提到: 】

: virtual unique_ptr<Child> Child::Clone() override;

: 最近有这种需求,子类提供克隆方法,返回自身类型的智能指针,不行。必须返回基类的智能指针?

DoorWay
DoorWay 05月08日

这玩意儿理论上的难点在哪儿?为啥不做成标准、编译器直接支持呢。

【 在 fanci 的大作中提到: 】

: 没啥好办法,返回基类的吧

Madlee
无竹居士 05月08日

主要是你的需求太奇葩。

【 在 DoorWay 的大作中提到: 】

: 这玩意儿理论上的难点在哪儿?为啥不做成标准、编译器直接支持呢。

DoorWay
DoorWay 05月08日

为什么奇葩?是error-prone,还是过于精细?我听不出好坏哈

我调研了,希望构造函数可以virtual,是非分之想。

这种clone后,希望直接是Child type,调用Child 方法,还算合理的要求吧?

【 在 Madlee 的大作中提到: 】

: 主要是你的需求太奇葩。

hgoldfish
老鱼 05月08日

多写一个 dynamic_cast<> 的事,不值得吧。。

java 的 clone() 同样返回 Object, 而不是子类。

【 在 DoorWay (DoorWay) 的大作中提到: 】

: 为什么奇葩?是error-prone,还是过于精细?我听不出好坏哈

: 我调研了,希望构造函数可以virtual,是非分之想。

: 这种clone后,希望直接是Child type,调用Child 方法,还算合理的要求吧?

: ...................

z16166
Netguy 05月08日

看看CRTP有没可能实现这个需求

vonNeumann
劣币驱逐良币 | 少灌水 05月08日

遇到过,没想到很优雅的解决办法。后来干脆直接返回裸指针了,调用处用 unique_ptr 来接返回值。

【 在 DoorWay (DoorWay) 的大作中提到: 】

: virtual unique_ptr<Child> Child::Clone() override;

: 最近有这种需求,子类提供克隆方法,返回自身类型的智能指针,不行。必须返回基类的智能指针?

: 这种一般怎么设计解决?

: ...................

vonNeumann
劣币驱逐良币 | 少灌水 05月08日

unique_ptr 毕竟是库实现的,如果要支持,怕是得对所有可以隐式转换的类型都支持才行。。如果单独给 unique_ptr/shared_ptr 开口子那太难看。。

【 在 DoorWay (DoorWay) 的大作中提到: 】

: 这玩意儿理论上的难点在哪儿?为啥不做成标准、编译器直接支持呢。

vonNeumann
劣币驱逐良币 | 少灌水 05月08日

不奇葩啊,裸指针从 C++98 开始就支持这样写,只是智能指针不行

【 在 Madlee (无竹居士) 的大作中提到: 】

: 主要是你的需求太奇葩。

DoorWay
DoorWay 05月08日

有一点感觉了。其它语言呢,上面有大侠提到jvav也不行,有行的语言不?

【 在 vonNeumann 的大作中提到: 】

: unique_ptr 毕竟是库实现的,如果要支持,怕是得对所有可以隐式转换的类型都支持才行。。如果单独给 unique_ptr/shared_ptr 开口子那太难看。。

DoorWay
DoorWay 05月08日

倒不是怕效率损失,工作的项目控制没有这么精细。

就是使用的不方便,读起来别扭,或许读的不够多。:-)

抑或为了形式的美感,一时思维的误区?

【 在 hgoldfish 的大作中提到: 】

: 多写一个 dynamic_cast<> 的事,不值得吧。。

: java 的 clone() 同样返回 Object, 而不是子类。

hgoldfish
老鱼 05月08日

我觉得写 c/cpp 时要不辞劳苦,把自己当成人肉编译器。追求效率和精准,而不是去追求代码的优雅。

写 python 时则相反,效率不值一分钱,代码优雅实现无误才是王道。

两个语言结合起来用,就无敌了。

【 在 DoorWay (DoorWay) 的大作中提到: 】

: 倒不是怕效率损失,工作的项目控制没有这么精细。

: 就是使用的不方便,读起来别扭,或许读的不够多。:-)

: 抑或为了形式的美感,一时思维的误区?

: ...................

here080
hero080 05月08日

这个问题的核心实质在于此处返回值是有实际物理内存要求的。如果允许子类重写的函数返回不同类型,那有可能该类型的大小跟父类返回类型大小不同。

基于这个原因,标准里只有指针和引用才有可能covariance

除非将unique_ptr作为语言内置功能,否则以类库的身份是不行的。

【 在 DoorWay 的大作中提到: 】

: virtual unique_ptr<Child> Child::Clone() override;

: 最近有这种需求,子类提供克隆方法,返回自身类型的智能指针,不行。必须返回基类的智能指针?

: 这种一般怎么设计解决?

here080
hero080 05月08日

不是吧,java当然是返回子类了。

java里没有值语义,全是指针,天生就covariance了

【 在 hgoldfish 的大作中提到: 】

: 多写一个 dynamic_cast<> 的事,不值得吧。。

: java 的 clone() 同样返回 Object, 而不是子类。

here080
hero080 05月08日

无法支持,隐形转换不保证大小相同啊。

如果要支持,估计得新加入covariance转换的概念了。

【 在 vonNeumann 的大作中提到: 】

: unique_ptr 毕竟是库实现的,如果要支持,怕是得对所有可以隐式转换的类型都支持才行。。如果单独给 unique_ptr/shared_ptr 开口子那太难看。。

here080
hero080 05月08日

少敲字不代表优雅。算法意义上的效率才是优雅。

【 在 hgoldfish 的大作中提到: 】

: 我觉得写 c/cpp 时要不辞劳苦,把自己当成人肉编译器。追求效率和精准,而不是去追求代码的优雅。

: 写 python 时则相反,效率不值一分钱,代码优雅实现无误才是王道。

: 两个语言结合起来用,就无敌了。

: ...................

here080
hero080 05月08日

如果你一定要这么搞,可以用一虚一实:

class Base {

protected:

virtual Base* CloneData();

public:

unique_ptr<Base> clone() { return {CloneData()}; }

};

class Derived {

protected:

Derived* CloneData() override;

};

【 在 DoorWay 的大作中提到: 】

: 为什么奇葩?是error-prone,还是过于精细?我听不出好坏哈

: 我调研了,希望构造函数可以virtual,是非分之想。

: 这种clone后,希望直接是Child type,调用Child 方法,还算合理的要求吧?

: ...................

leadu
leadu 05月08日

c#去年才支持上,别的语言可能得等等

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/covariant-returns

【 在 DoorWay 的大作中提到: 】

: 有一点感觉了。其它语言呢,上面有大侠提到jvav也不行,有行的语言不?

: :