2015-12-04 1 views
1

Я работаю над проектом с чрезвычайно низкой единицей тестирования. У нас почти нулевое модульное тестирование, и каждый API статичен.Является ли C++ компоновщик умным о виртуальных методах, используемых только из одного класса в программе?

Чтобы иметь возможность модульного тестирования некоторые из моего кода я создаю оберток как

class ApiWrapper { 

    virtual int Call(foo, bar) { 
     return ApiCall(foo, bar); 
    } 
}; 

Сейчас в моих функций вместо:

int myfunc() { 
    APiCall(foo, bar);   
} 

я:

int myfunc(ApiWrapper* wrapper) { 
    wrapper->Call(foo, bar);   
} 

Этот путь Я могу издеваться над такой функциональностью. Проблема в том, что некоторые коллеги жалуются на то, что производственный код не должен быть затронут из-за возможностей проверки - нонсенс, который я знаю, но реальность.

В любом случае, я считаю, что где-то я где-то читал, что компиляторы действительно умны в замене неиспользуемого полиморфного поведения на прямой вызов ... или если нет класса, который переопределяет виртуальный метод, он становится «нормальным».

Я экспериментировал, и на gcc 4.8 он не встроен или не вызывает виртуальный метод, а создает vt.

Я попытался Google, но я ничего не нашел об этом. Является ли это чем-то, или я забываю ... или я должен что-то сделать, чтобы объяснить это компоновщику, флаг оптимизации или что-то еще?

Обратите внимание, что в процессе производства этот класс является окончательным, в тестовой среде это не так. Это именно то, что должен уметь компоновщик и обнаружить.

+1

Я хочу, чтобы вы это искали: http://stackoverflow.com/questions/733737/are-inline-virtual-functions-really-a-non-sense – NathanOliver

+2

Мне непонятно, зачем нужны обертки , –

+0

, чтобы иметь возможность издеваться над функциональностью, когда я проверяю свой код, который зависит от него – gsf

ответ

1

Компилятор C++ заменит полиморфный вызов прямым вызовом, если он точно знает, что такое фактический тип.

Таким образом, в следующем фрагменте кода, она будет оптимизирована:

void f() { 
    ApiWrapper x; 
    x.Call(); // Can be replaced 
} 

Но в общем случае, она не может:

void f(ApiWrapper* wrapper) { 
    wrapper->Call(); // Cannot be replaced 
} 

Вы также добавили два условия на ваш вопрос:

Если нет класса, который переопределяет виртуальный метод, он становится «нормальным».

Это не поможет. Ни компилятор C++, ни компоновщик не будут рассматривать совокупность классов для поиска, существует ли какой-либо наследник. В любом случае это бесполезно, так как вы всегда можете динамически загружать экземпляр нового класса.

Кстати, эта оптимизация действительно выполняется некоторыми JVM (называемой девиртуализацией), поскольку на землях Java есть классный загрузчик, который знает, какие классы в настоящее время загружаются.

в производстве этого класса является окончательным

Это поможет! Например, Clang преобразует виртуальные вызовы в не виртуальные вызовы, если класс метода/метода помечен final.

Смежные вопросы