Animal
public abstract class Animal {
String name;
public Animal(String name) {
this.name = name;
}
}
Lion
public class Lion extends Animal {
public Lion(String name) {
super(name);
// TODO Auto-generated constructor stub
}
public void roar() {
System.out.println("Roar");
}
}
Deer
public class Deer extends Animal {
public Deer(String name) {
super(name);
}
public void runAway() {
System.out.println("Running...");
}
}
TestAnimals
public class TestAnimals {
public static void main(String[] args) {
Animal lion = new Lion("Geo");
Animal deer1 = new Deer("D1");
Animal deer2 = new Deer("D2");
List li = new ArrayList();
li.add(lion);
li.add(deer1);
li.add(deer2);
for (Animal a : li) {
if (a instanceof Lion) {
Lion l = (Lion) a;
l.roar();
}
if (a instanceof Deer) {
Deer l = (Deer) a;
l.runAway();
}
}
}
}
Есть ли лучший способ перебирать список без использования приведений? В приведенном выше случае это нормально, но если у вас есть много расширений базового класса, тогда нам понадобится и столько блоков if. { public: tester (int * arr_, int sz_): arr (arr_), sz (sz_) {} ...
Я столкнулся с противоречивым поведением оптимизации с различными компиляторами для следующего кода:
class tester
{
public:
tester(int* arr_, int sz_)
: arr(arr_), sz(sz_)
{}
int doadd()
{
sm = 0;
for (int n = 0; n < 1000; ++n)
{
for (int i = 0; i < sz; ++i)
{
sm += arr[i];
}
}
return sm;
}
protected:
int* arr;
int sz;
int sm;
};
Функция doadd
имитирует некоторый интенсивный доступ к членам (в этом вопросе дополнительно игнорируйте переполнения). По сравнению с аналогичным кодом, реализованным как функция:
int arradd(int* arr, int sz)
{
int sm = 0;
for (int n = 0; n < 1000; ++n)
{
for (int i = 0; i < sz; ++i)
{
sm += arr[i];
}
}
return sm;
}
Метод doadd
работает примерно в 1,5 раза медленнее, чем функция arradd
при компиляции в режиме выпуска с Visual C ++ 2008. Когда Я изменяю метод doadd
, чтобы он выглядел следующим образом (псевдоним всех членов с помощью locals):
int doadd()
{
int mysm = 0;
int* myarr = arr;
int mysz = sz;
for (int n = 0; n < 1000; ++n)
{
for (int i = 0; i < mysz; ++i)
{
mysm += myarr[i];
}
}
sm = mysm;
return sm;
}
Время выполнения становится примерно таким же. Правильно ли я заключил, что компилятор Visual C ++ упустил эту оптимизацию? g ++
, кажется, делает это лучше и запускает и функцию-член, и обычную функцию с одинаковой скоростью при компиляции с -O2
или -O3
.
Тестирование выполняется путем вызова члена doadd
и функции arradd
для некоторого достаточно большого массива (размером в несколько миллионов целых чисел).
EDIT: Some fine- Детальное тестирование показывает, что главным виновником является член sm
. Замена всех остальных локальными версиями по-прежнему увеличивает время выполнения, но как только я заменю sm
на mysm
, время выполнения станет равным версии функции.
Разочарован ответы (извините, ребята), Я стряхнул с себя лень и погрузился в листинги разборки этого кода. Мой ответ ниже обобщает результаты. Вкратце: это не имеет ничего общего с наложением имен, это связано с развертыванием цикла и с некоторыми странными эвристиками, которые MSVC применяет при принятии решения, какой цикл развернуть.