最好跳过代码并阅读评论,以便快速了解我尝试做的事情,但是我需要尝试描述更多重要细节:
我想将一个成员函数添加到通过类heirarchy继承的类中。我想这样做,以便派生类不必重新键入任何代码或做任何特殊的事情来自动获取此功能,我想避免使用宏。此函数也应该由编译后生成的任何子类继承(这是其他人将扩展的平台的一部分)。
该函数是一个调试函数,它跟踪指向类实例的自定义智能指针(很像std :: shared_ptr) - 我希望能够找出为什么给定实例被保存在内存,这意味着我需要知道指向它的指针。定制的智能指针是模板化的,我想强制使用用作参数的智能指针的特化与实例的静态类型的类型匹配。
由于这是在一个框架中,因此在编译后为扩展层次结构的人启用此功能是非常重要的。
这是使用Visual Studio 2010在Windows上编译的。我们很快就会转向VS 2015,但我不想等待。我们也主要是跨平台(我们只在必要时为其他平台关闭了一些东西)。如果有一个解决方案需要C ++ 11/14/17 /更高版本,我仍然希望听到它的兴趣。
我觉得我需要同时制作模板化和专业化的功能,专门用某种类型的“自我”,但我不知道如何让子类获得基本上复制粘贴的内容而不是继承的代码。我也理解(我认为)这个函数不适合虚拟化,但我也想阻止子类获取父类'专业化。
我认为我可以选择一些选项,但我想知道我有没有想过的更好的事情:
我完全期望完全不同的设计模式是最好的解决方案,但我还没有想到这样的解决方案。
我真的认为编译器能够知道我需要它支持的所有内容,但是我不确定语言是否会这样做。
我也非常感谢有关如何更好地说出这个问题的一些帮助或反馈。我自己很难解决这个问题,更不用说为别人理解了。
template<class T>
class CustomSmartPointer {};
class Base {
public:
void doSomething(CustomSmartPointer<Base> arg) {} //Should be able to say something like CustomSmartPointer<Self> instead, where the compiler knows what I mean by Self
};
class Derived : public Base {
public:
void doSomething(CustomSmartPointer<Derived> arg) {} //Shouldn't have to specify this declaration, or code, again, as it is direcly copy-pastable from above
};
class Derived2 : public Base {};
void main() {
Base b;
Derived d;
Derived2 d2;
CustomSmartPointer<Base> cb;
CustomSmartPointer<Derived> cd;
b.doSomething(cb);
d.doSomething(cd);
d2.doSomething(cb); //This shouldn't compile, as cb is the wrong type for the specialisation that should exist for Derived2::doSomething
}
答案 0 :(得分:2)
我将重复我的评论,这解释了为什么运行时继承不适合:void doSomething(CustomSmartPointer<Base> arg)
和void doSomething(CustomSmartPointer<Derived> arg)
是不相关的成员函数(尽管它们是{{1}内的同名重载{1}})。如果您不希望在Derived
中使用void doSomething(CustomSmartPointer<Base> arg)
,则在您的情况下运行时继承是不合适的。
CRTP可能是您正在寻找的。 p>
Derived
当然,这意味着派生类不会有共同的父级。您可以为template <class T>
struct Base {
void doSomething(CustomSmartPointer<T>);
};
struct Derived: Base<Derived> {}; // will inherit void doSomething(CustomSmartPointer<Derived>) from parent
struct Derived2: Base<Derived2> {}; // will inherit void doSomething(CustomSmartPointer<Derived2>) from parent
非模板父级提供解决方法,但不能将其用作Base
的接口。
另一方面,如果你不能修改doSomething
,Base
必须继承Derived
那么就没有办法避免继承成员函数,如果它是一个bug称之为,抓住错误编译时间会很棘手。但是,您可以覆盖Base
中的doSomething(CustomSmartPointer<Base>)
并抛出运行时异常以捕获错误运行时。
答案 1 :(得分:1)
实现这一目标的一种可能方法可能是CRTP,尽管它可能看起来很难看并且使继承复杂化:
template<class T>
class CustomSmartPointer {};
template <class D>
class Base {
public:
void doSomething(CustomSmartPointer<D> arg) {}
};
class Derived : public Base<Derived> {};
class Derived2 : public Base<Derived2> {};
int main() {
Derived d;
Derived2 d2;
CustomSmartPointer<Derived> cd;
d.doSomething(cd);
d2.doSomething(cd); //does not compile
return 0;
}
答案 2 :(得分:0)
当您使用模板编译c ++文件时会发生什么,编译器会在需要时创建专用模板函数。 (这是你错误中的instantiated from here
)。
在您的情况下,编译器将创建两个类:CustomSmartPointerBase
和CustomSmartPointerDerived
。
现在你在base:doSomething(CustomSmartPointerBase)
中创建一个函数。此函数也可在Derived
类中使用,因为它是一个子类。
doSomething
中的Derived
声明不会覆盖Base
中的Derived
声明,因为它采用不同的类型作为参数,因此它会过载。
这意味着doSomething
类中包含两个函数:CustomSmartPointer
用于cout << "doSomethingBase" << endl;
。
您可以通过在相应的cout << "doSomethingDerived" <<endl;
功能中添加doSomething
和{{1}}语句并运行代码来尝试此操作。或者更好,使用调试器逐步完成它。