我很好奇Expression.Compile与代码中的lambda表达式和直接方法使用的性能如何,以及直接方法调用与虚方法调用(伪代码):
var foo = new Foo();
var iFoo = (IFoo)foo;
foo.Bar();
iFoo.Bar();
(() => foo.Bar())();
(() => iFoo.Bar())();
Expression.Compile(foo, Foo.Bar)();
Expression.Compile(iFoo, IFoo.Bar)();
Expression.CompileToMethod(foo, Foo.Bar);
Expression.CompileToMethod(iFoo, IFoo.Bar);
MethodInfo.Invoke(foo, Foo.Bar);
MethodInfo.Invoke(iFoo, IFoo.Bar);
Run Code Online (Sandbox Code Playgroud) 有没有真正的理由不在 C++中使成员函数虚拟化?当然,总会存在性能参数,但由于虚函数的开销相当低,因此在大多数情况下似乎并不存在.
在另一方面,我已经被咬了好几次与遗忘做一个功能的虚拟那应该是虚拟的.这似乎是一个比表现更大的争论.那么有没有理由不默认将成员函数设为虚拟?
在C++中,我必须明确指定'virtual'关键字以使成员函数'overridable',因为当成员函数被覆盖时,会产生创建虚拟表和vpointer的开销(因此每个成员函数都隐式不能覆盖表现原因).
当子类提供具有相同名称和签名的单独实现时,它还允许隐藏成员函数(如果未覆盖).
在C#中也使用相同的技术.我想知道为什么Java摆脱了这种行为,并默认使每个方法都可以覆盖,并提供了在显式使用'final'关键字时禁用覆盖行为的能力.
我现在正在课堂上学习C++,而且我不太熟悉纯虚函数.我知道它们稍后在派生类中概述,但是如果你要在派生类中定义它,为什么要将它声明为等于0?
考虑以下示例:
#include <iostream>
using namespace std;
class base
{
public:
virtual int func()
{
cout << "vfunc in base class\n";
return 0;
}
};
class derived: public base
{
public:
double func()
{
cout << "vfunc in derived class\n";
return 0;
}
};
int main()
{
base *bptr = new derived;
bptr->func();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译器为上面的代码提供了一个错误,即覆盖函数存在冲突类型.为什么不能使用不同的返回类型覆盖派生类中的函数?
我相信,为了覆盖一个函数,需要在派生类中重新定义基类虚方法.要重新定义方法,方法的签名必须相同.由于返回类型不是签名的一部分,我相信即使返回类型有差异,该方法仍将被重新定义?在上述代码的情况下,func在派生类中使用不同的返回类型重新定义虚函数.但是编译器会抛出错误.我的理解是否正确?
class base{
.....
virtual void function1();
virtual void function2();
};
class derived::public base{
int function1();
int function2();
};
int main()
{
derived d;
base *b = &d;
int k = b->function1() // Why use this instead of the following line?
int k = d.function1(); // With this, the need for virtual functions is gone, right?
}
Run Code Online (Sandbox Code Playgroud)
我不是CompSci工程师,我想知道这一点.如果我们可以避免基类指针,为什么要使用虚函数?
我正在评估将一个实时软件从C /汇编语言重写为C++ /汇编语言(由于与代码问题无关的原因,在汇编时绝对需要这样做).
中断带有3 kHz频率,对于每个中断,大约200个不同的事情将按顺序完成.处理器以300 MHz运行,为我们提供100,000个周期来完成这项工作.这已在C中用函数指针数组求解:
// Each function does a different thing, all take one parameter being a pointer
// to a struct, each struct also being different.
void (*todolist[200])(void *parameters);
// Array of pointers to structs containing each function's parameters.
void *paramlist[200];
void realtime(void)
{
int i;
for (i = 0; i < 200; i++)
(*todolist[i])(paramlist[i]);
}
Run Code Online (Sandbox Code Playgroud)
速度很重要.上述200次迭代每秒完成3000次,因此实际上我们每秒进行600,000次迭代.上面的for循环每次迭代编译为五个周期,总成本为每秒3,000,000个周期,即1%的CPU负载.汇编程序优化可能会将其降低到四个指令,但是我担心由于内存访问彼此接近等原因,我们可能会得到一些额外的延迟.简而言之,我相信这五个周期非常理想.
现在进行C++重写.我们做的那200件事情彼此有关.有一个参数的子集,它们都需要和使用,并具有各自的结构.在C++实现中,它们可以被巧妙地视为从公共基类继承:
class Base
{
virtual void Execute();
int something_all_things_need;
}
class Derived1 : Base
{
void Execute() { …Run Code Online (Sandbox Code Playgroud) 从C++/Java/C#背景开始我希望在Swift中看到虚拟方法,但是阅读swift文档我没有提到虚拟方法.
我错过了什么?
请考虑以下标准CRTP示例:
#include <iostream>
template<class Derived>
struct Base {
void f() { static_cast<Derived *>(this)->f(); }
void g() { static_cast<Derived *>(this)->g(); }
};
struct Foo : public Base<Foo> {
void f() { std::cout << 42 << std::endl; }
};
int main() {
Foo foo;
foo.f(); // just OK
foo.g(); // this will stack overflow and segfault
}
Run Code Online (Sandbox Code Playgroud)
如果这是常规虚拟继承,我可以将虚拟f和g方法标记为纯粹
struct Base {
virtual void f() = 0;
virtual void g() = 0;
};
Run Code Online (Sandbox Code Playgroud)
并获得关于Foo抽象的编译时错误.但是CRTP没有提供这样的保护.我可以以某种方式实现它吗?运行时检查也是可以接受的.我想过将this->f指针与比较static_cast<Derived …
斯科特在Effective C++上说,第3版,pg.43要创建一个抽象类,我们只需要给它一个纯虚拟析构函数:
class AWOV { // AWOV = "Abstract w/o Virtuals"
public:
virtual ~AWOV() = 0; // declare pure virtual destructor
};
Run Code Online (Sandbox Code Playgroud)
然后,他接着说有一个转折:我们必须为纯虚析构函数提供一个定义:
AWOV::~AWOW() {} // definition of pure virtual dtor
Run Code Online (Sandbox Code Playgroud)
我的问题是,通过指定= 0纯虚函数,我们说该函数不能对声明这个纯虚函数的类有任何定义.
为什么在这里为纯虚拟析构函数提供定义(即使它是空的)是可以的?
c++ ×8
oop ×2
polymorphism ×2
pure-virtual ×2
base-class ×1
c ×1
c# ×1
class ×1
crtp ×1
expression ×1
java ×1
lambda ×1
overriding ×1
performance ×1
real-time ×1
redefinition ×1
swift ×1
vtable ×1