这种情况下虚函数能使用模板代替吗?

2019-12-15 11:02:49 +08:00
 nyanyh

有两个 A、B 两个抽象类分别派生出几个类,我想在一类中加一个指针指向另一类的实例。大致代码如下:

class parentA {
public:
    virtual void func() = 0;

    parentB* ptrToAnother; // here
};

class classA1 : public parentA {
public:
    void func() override;
};

class classA2 : public parentA {
public:
    void func() override;
};


class parentB {
public:
    virtual void func() = 0;

    parentA* ptrToAnother; // here
};

class classB1 : public parentB {
public:
    void func() override;
};

class classB2 : public parentB {
public:
    void func() override;
};


classB1 b1;
classA1 a1;
a1.ptrToAnother = &b1;
b1.ptrToAnother = &a1;

a1.ptrToAnother->func();
b1.ptrToAnother->func();

这样就可以通过 ptrToAnother 指针访问另一个类。但是想换成模板实现就爆炸了:

template<typename AnotherClassName>
class parentA {
public:
    virtual void func() = 0;

    AnotherClassName* ptrToAnother; // here
};

template<typename AnotherClassName>
class classA1 : public parentA<AnotherClassName> {
public:
    void func() override;
};

template<typename AnotherClassName>
class classA2 : public parentA<AnotherClassName> {
public:
    void func() override;
};


template<typename AnotherClassName>
class parentB {
public:
    virtual void func() = 0;

    AnotherClassName* ptrToAnother; // here
};

template<typename AnotherClassName>
class classB1 : public parentB<AnotherClassName> {
public:
    void func() override;
};

template<typename AnotherClassName>
class classB2 : public parentB<AnotherClassName> {
public:
    void func() override;
};


// 不能编译,缺少模板参数
classA1<classB1> a1;
classB1<classA1> b1;

a1.ptrToAnother->func();
b1.ptrToAnother->func();

3026 次点击
所在节点    C++
7 条回复
gwy15
2019-12-15 13:05:07 +08:00
用模板,ClassA1 的模板参数得是一个具体的类而不是模板类,这里的依赖变成了
type(a1) = classA1<type(b1)> = classA1<classB1<type(a1)>>
所以构成了循环依赖,模板系统里这个方程的解是不存在的,模板没法展开。

如果不关心具体的实现,这样可以通过编译。但是调用的是 derived<int>,不是你想要的那个结果
```c++
classA1<classB1<int>> a1;
classB1<classA1<int>> b1;

a1.ptrToAnother = new classB1<int>();
b1.ptrToAnother = new classA1<int>();

a1.ptrToAnother->func();
b1.ptrToAnother->func();
```
amai0w0
2019-12-15 13:23:50 +08:00
在 template 里边的变量必须是特化的,如果里面是另一个另一个 template 类的话什么应该是 template<template<typename> class AntherClassName,typename E>, 然后用 AntherClassName<E>调用。但是这里的 classB1 又是用 classA1 特化,感觉无解了。所以我觉得还是得像前面那样实例化以后再注入。
插眼等一个 dalao
nyanyh
2019-12-15 13:33:00 +08:00
@amai0w0 #2
@gwy15 #1
刚才发现了一种非常神奇的写法 http://qscribble.blogspot.com/2008/06/circular-template-references-in-c.html



但是适用于两个固定的类 A 和 B,我这种情况有两堆派生类,如果给 MyCombo 加模板的话就又产生循环依赖的问题了
secondwtq
2019-12-15 14:06:29 +08:00
试试用 #3 的方法加上 #2 的 HKT

template <template<typename> class A, template<typename> class B>
struct MyCombo {
typedef A<MyCombo<A, B>> a_t;
typedef B<MyCombo<A, B>> b_t;
};

Aa<MyCombo<Aa, Bb>> a;
Bb<MyCombo<Aa, Bb>> b;
nyanyh
2019-12-15 14:16:23 +08:00
@secondwtq #4 声明变量可以编译,但是给 prtToAnother 赋值就会出错了
a.prtToPair = &b;
^~
error: assigning to 'MyCombo<DerivedA, DerivedB> *' from incompatible type 'DerivedB<MyCombo<DerivedA, DerivedB> > *'
secondwtq
2019-12-15 14:19:23 +08:00
@nyanyh 你 check 下代码,你这个“prtToPair”看起来是个 MyCombo * ...
wutiantong
2019-12-16 10:43:02 +08:00
模版对应编译时多态,继承对应运行时多态,

你走的路子还是继承的,非要用模版来掺一脚令人费解啊。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/629161

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX