Tôi đã viết một ví dụ đơn giản, ước tính thời gian trung bình gọi hàm ảo, sử dụng giao diện lớp cơ sở và dynamic_cast và gọi hàm không phải ảo. Đây là địa chỉ:Tại sao gọi hàm ảo nhanh hơn dynamic_cast?
#include <iostream>
#include <numeric>
#include <list>
#include <time.h>
#define CALL_COUNTER (3000)
__forceinline int someFunction()
{
return 5;
}
struct Base
{
virtual int virtualCall() = 0;
virtual ~Base(){};
};
struct Derived : public Base
{
Derived(){};
virtual ~Derived(){};
virtual int virtualCall(){ return someFunction(); };
int notVirtualCall(){ return someFunction(); };
};
struct Derived2 : public Base
{
Derived2(){};
virtual ~Derived2(){};
virtual int virtualCall(){ return someFunction(); };
int notVirtualCall(){ return someFunction(); };
};
typedef std::list<double> Timings;
Base* createObject(int i)
{
if(i % 2 > 0)
return new Derived();
else
return new Derived2();
}
void callDynamiccast(Timings& stat)
{
for(unsigned i = 0; i < CALL_COUNTER; ++i)
{
Base* ptr = createObject(i);
clock_t startTime = clock();
for(int j = 0; j < CALL_COUNTER; ++j)
{
Derived* x = (dynamic_cast<Derived*>(ptr));
if(x) x->notVirtualCall();
}
clock_t endTime = clock();
double callTime = (double)(endTime - startTime)/CLOCKS_PER_SEC;
stat.push_back(callTime);
delete ptr;
}
}
void callVirtual(Timings& stat)
{
for(unsigned i = 0; i < CALL_COUNTER; ++i)
{
Base* ptr = createObject(i);
clock_t startTime = clock();
for(int j = 0; j < CALL_COUNTER; ++j)
ptr->virtualCall();
clock_t endTime = clock();
double callTime = (double)(endTime - startTime)/CLOCKS_PER_SEC;
stat.push_back(callTime);
delete ptr;
}
}
int main()
{
double averageTime = 0;
Timings timings;
timings.clear();
callDynamiccast(timings);
averageTime = (double) std::accumulate<Timings::iterator, double>(timings.begin(), timings.end(), 0);
averageTime /= timings.size();
std::cout << "time for callDynamiccast: " << averageTime << std::endl;
timings.clear();
callVirtual(timings);
averageTime = (double) std::accumulate<Timings::iterator, double>(timings.begin(), timings.end(), 0);
averageTime /= timings.size();
std::cout << "time for callVirtual: " << averageTime << std::endl;
return 0;
}
Dường như callDynamiccast mất gần gấp hai lần.
time for callDynamiccast: 0.000240333
time for callVirtual: 0.0001401
Bất cứ ý tưởng tại sao không?
CHỈNH SỬA: tạo đối tượng được thực hiện trong chức năng tách biệt ngay bây giờ, do đó trình biên dịch không biết loại thực. Gần như cùng một kết quả.
EDITED2: tạo hai loại khác nhau của một đối tượng có nguồn gốc.
Bạn có thể cần chạy nhiều lần lặp lại hơn để có được một thước đo thống kê hợp lý. Bạn có đang biên dịch ở cài đặt tối ưu hóa cao nhất không? –
Tôi đã thử với nhiều lần lặp lại hơn, nhưng kết quả là như nhau. Tất cả các tối ưu hóa đều tắt. Tôi đã sử dụng MSVS2008. –
Bài kiểm tra của bạn không hợp lệ, vì trình biên dịch có thể dễ dàng tối ưu hóa cả cuộc gọi ảo (thành cuộc gọi không ảo) và dynamic_cast (về cơ bản là noop), vì nó biết rằng 'ptr' thực sự trỏ đến đối tượng' Derived'. –