C++ 什么';这是C+中最接近的东西+;追溯定义已定义类的超类?
假设我上课C++ 什么';这是C+中最接近的东西+;追溯定义已定义类的超类?,c++,superclass,subclassing,idioms,C++,Superclass,Subclassing,Idioms,假设我上课 class A { protected: int x,y; double z,w; public: void foo(); void bar(); void baz(); }; 在我的代码和其他代码中定义和使用。现在,我想写一些库,它可以很好地在A上运行,但实际上它更通用,并且能够在: class B { protected: int y; double z; public: void bar(); }; 我确实希望我
class A {
protected:
int x,y;
double z,w;
public:
void foo();
void bar();
void baz();
};
在我的代码和其他代码中定义和使用。现在,我想写一些库,它可以很好地在A上运行,但实际上它更通用,并且能够在:
class B {
protected:
int y;
double z;
public:
void bar();
};
我确实希望我的库是通用的,所以我定义了一个B类,它的API就是这样
我希望能够告诉编译器——不是在我不再控制的A的定义中,而是在其他地方,可能在B的定义中:
听着,请试着把B
看作a
的超类。因此,特别是在内存中进行布局,这样,如果我将A*
重新解释为B*
,我的代码预期B*
s将起作用。然后请实际接受A*
作为B*
(以及A&
作为B&
等)
在C++中,我们可以用另一种方式来做这件事,即如果B是我们不控制的类,我们可以用“代码>类A:公共B{} }/Cuth>执行一个“子类已知类”操作;我知道C++没有相反的机制——“超类,一个新B类已知的类A”。我的问题是-这个机制最接近的近似值是什么
注意事项:
- 这完全是编译时,而不是运行时
不能有任何更改。我只能修改A类
和既知道B
又知道A
的代码的定义。其他人仍然会使用classB
,如果我想让我的代码与他们的代码交互,我也会这样做A
- 这最好是“可扩展”到多个超类。因此,也许我还有
,它的行为应该类似于类C{protected:intx;double w;public:void baz();}
的超类李>a
template <class Superclass>
class Class : public Superclass
{
};
请注意,
dynamic\u cast
将到达A*
给定的Superclass*
指针,反之亦然。同上Class*
指针。在这一点上,你正接近组成、特征和概念。你可以做以下几点:
class C
{
struct Interface
{
virtual void bar() = 0;
virtual ~Interface(){}
};
template <class T>
struct Interfacer : Interface
{
T t;
Interfacer(T t):t(t){}
void bar() { t.bar(); }
};
std::unique_ptr<Interface> interface;
public:
template <class T>
C(const T & t): interface(new Interfacer<T>(t)){}
void bar() { interface->bar(); }
};
C类
{
结构接口
{
虚拟空心条()=0;
虚拟~Interface(){}
};
模板
结构接口器:接口
{
T;
接口器(T):T(T){}
void bar(){t.bar();}
};
std::唯一的ptr接口;
公众:
模板
C(常数T&T):接口(新接口(T)){}
void bar(){interface->bar();}
};
其思想是使用类型擦除(即
接口
和接口
类)在封面下,允许C
获取任何您可以调用的bar
,然后您的库将获取C
类型的对象。如果不更改类,则无法更改类的行为。在定义了a
之后,确实没有添加父类的机制
我只能修改B的定义以及同时了解A和B的代码
您不能更改A
,但可以更改使用A
的代码。因此,您可以使用另一个继承自B
(我们称之为D
)的类,而不是使用A
。我认为这是最接近理想的机制
D
如果有用,可以将A
重新用作子对象(可能作为基础)
这最好是“可扩展”到多个超类
D
可以根据需要继承任意多个超类
演示:
class D : A, public B, public C {
public:
D(const A&);
void foo(){A::foo();}
void bar(){A::bar();}
void baz(){A::baz();}
};
现在,如果A
继承了B
和C
,则D
的行为与A
的行为完全相同
公开继承A
将允许删除所有委托样板文件:
class D : public A, public B, public C {
public:
D(const A&);
};
然而,我认为这可能会在不知道B
的情况下使用A
的代码和知道B
的代码(因此使用D
)之间造成混淆。使用D
的代码可以轻松处理A
,但不能反过来处理
完全不继承A
,而是使用成员将允许您不复制A
来创建D
,而是引用现有成员:
class D : public B, public C {
A& a;
public:
D(const A&);
void foo(){a.foo();}
void bar(){a.bar();}
void baz(){a.baz();}
};
这显然有可能导致对象生命周期出错。这可以通过共享指针来解决:
class D : public B, public C {
std::shared_ptr<A> a;
public:
D(const std::shared_ptr<A>&);
void foo(){a->foo();}
void bar(){a->bar();}
void baz(){a->baz();}
};
D类:公共B、公共C{
std::共享的ptr a;
公众:
D(const std::shared_ptr&);
void foo(){a->foo();}
void bar(){a->bar();}
void baz(){a->baz();}
};
但是,如果不知道
B
或D
的其他代码也使用共享指针,那么这可能只是一个选项。普通模板会这样做,当您错误地使用它们时,编译器会通知您
而不是
void BConsumer1(std::vector<B*> bs)
{ std::for_each(bs.begin(), bs.end(), &B::bar); }
void BConsumer2(B& b)
{ b.bar(); }
class BSubclass : public B
{
double xplusz() const { return B::x + B::z; }
}
void BConsumer1(标准::向量bs)
{std::for_each(bs.begin()、bs.end()、&B::bar);}
无效B消费2(B&B)
{b.bar();}
B类子类:公共B类
{
双xplusz()常量{返回B::x+B::z;}
}
你写
template<typename Blike>
void BConsumer1(std::vector<Blike*> bs)
{ std::for_each(bs.begin(), bs.end(), &Blike::bar); }
template<typename Blike>
void BConsumer2(Blike& b)
{ b.bar(); }
template<typename Blike>
class BSubclass : public Blike
{
double xplusz() const { return Blike::x + Blike::z; }
}
模板
void BConsumer1(标准::向量bs)
{std::for_each(bs.begin()、bs.end()、&Blike::bar);}
模板
无效b消费2(Blike&b)
{b.bar();}
模板
类B子类:公共闪电
{
双xplusz()常量{return Blike::x+Blike::z;}
}
您可以像这样使用BConsumer1和BConsumer2
std::vector<A*> as = /* some As */
BConsumer1(as); // deduces to BConsumer1<A>
A a;
BConsumer2(a); // deduces to BConsumer2<A>
std::vector<B*> bs = /* some Bs */
BConsumer1(bs); // deduces to BConsumer1<B>
// etc
std::vector as=/*一些as*/
b消费者1(作为);//推断出B消费者1
A A;
b消费者2(a);//推断出B消费者2
std::vector bs=/*某些bs*/
b消费者1(bs);//推断出B消费者1
//等
您将拥有BSubclass
和BSubclass
,作为使用
std::vector<A*> as = /* some As */
BConsumer1(as); // deduces to BConsumer1<A>
A a;
BConsumer2(a); // deduces to BConsumer2<A>
std::vector<B*> bs = /* some Bs */
BConsumer1(bs); // deduces to BConsumer1<B>
// etc
namespace details_ {
template<class T, class=void>
struct has_bar : std::false_type {};
template<class T>
struct has_bar<T, std::void_t<decltype(std::declval<T>().bar())>> : std::true_type {};
}
template<class T>
constexpr bool has_bar = details_::has_bar<T>::value;
template<class T>
std::enable_if_t<has_bar<T>> use_bar(T *t) { t->bar(); }
template<class T>
std::enable_if_t<!has_bar<T>> use_bar(T *) {
static_assert(false, "Cannot use bar if class does not have a bar member function");
}