Предположим, вам даны два класса A
и B
, интерфейс которых неизвестен заранее. Цель состоит в том, чтобы "объединить" A
и B
в новый класс AB
во время компиляции.
Объединив, я имею в виду, что все функции-члены и все переменные-члены, а также все типы A
и B
присутствуют в AB
с той же реализацией. Наследования классического класса не хватает; Мне нужно иметь его во время компиляции, потому что диспетчеризация времени выполнения является дорогостоящей в моем приложении. Наивное решение было бы создать экземпляр каждого класса и направить любой вызов; однако это не является общим, поскольку мы предполагаем, что интерфейс не должен быть зафиксирован заранее.
Использование понятий С++ 11 прекрасно, если это помогает. Возможна ошибка компилятора в случае конфликта в интерфейсах A
и B
Классы реализуют функции утилиты, которые основаны на некоторых внешних данных и передаются как параметр шаблона. Существует несколько типичных утилит, которые часто используются и которые я хочу учитывать (классы A
, B
, C
), но не все они всегда применимы (если, например, применимы только A
и B
, то я хочу использовать служебную программу AB
). Код очень низкоуровневый, и функции полезности вызываются очень часто в критическом по времени цикле.
Для не виртуальных функций наследование не накладывается на наследование. Поэтому просто не объявляйте ни одного из членов A
или B
как virtual
и никакая virtual
таблица не будет создана компилятором.
Минималистский пример
struct A { void f() { /* ... */ } };
struct B { void g() { /* ... */ } };
struct AB : public A, public B { }; // Provides both f and g.
Nb, если A
и B
перекрываются, компилятор будет жаловаться на двусмысленности.
(Этот ответ основан на комментариях и дается для полноты, кредиты для комментаторов.)
Я уверен, что это уже было рассмотрено в другом месте - то, что вы ищете, - это статическое наследование. Два шаблона, реализующие это, - это основанный на политике дизайн и любопытно повторяющиеся шаблоны. Остерегайтесь проблем с перегрузкой.
#include <iostream>
using namespace std;
class A
{
public:
int a;
A() : a(0) {}
int foo_A() { return a; }
};
class B
{
public:
int b;
B() : b(1) {}
int foo_B() { return b; }
};
template<class stinh1, class stinh2>
class AB : public stinh1, public stinh2
{
};
int main()
{
AB<A,B> ab;
cout << ab.foo_A() << endl << ab.foo_B() << endl;
ab.a = 2;
ab.b = 3;
cout << ab.foo_A() << endl << ab.foo_B() << endl;
}
AB
быть шаблоном?
Наследование - это один из способов (возможно, предпочтительный). У вас будет небольшая проблема, если A и B содержат методы с подписями (одно и то же имя и одинаковые параметры), это трудно преодолеть без знания API перед началом работы. Вы можете попытаться проанализировать код статически, попросить программу прочитать код как текст, проанализировать API и создать новый текст вместе с API вместе, вам нужно будет решить, что делать с той же проблемой подписи (вы называете оба? в каком порядке? и т.д.). Это решение намного, намного сложнее и подвержено ошибкам.
A
иB