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
    又知道
    B
    的代码的定义。其他人仍然会使用class
    A
    ,如果我想让我的代码与他们的代码交互,我也会这样做
  • 这最好是“可扩展”到多个超类。因此,也许我还有
    类C{protected:intx;double w;public:void baz();}
    ,它的行为应该类似于
    a
    的超类
我知道C++没有相反的机制——“超类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");
}