我刚刚在一些代码中发现了这个:
class Foo {
[...]
private:
virtual void Bar() = 0;
[...]
}
Run Code Online (Sandbox Code Playgroud)
这有什么用途吗?
(我试图将一些代码从VS移植到G ++,这引起了我的注意)
我对虚拟对象大小有一些疑问.
1)虚函数
class A {
public:
int a;
virtual void v();
}
Run Code Online (Sandbox Code Playgroud)
A类的大小是8字节....一个整数(4个字节)加上一个虚拟指针(4个字节)很清楚!
class B: public A{
public:
int b;
virtual void w();
}
Run Code Online (Sandbox Code Playgroud)
B级的大小是多少?我使用sizeof B测试,它打印12
这是否意味着只有一个vptr,即使B类和A类都有虚函数?为什么只有一个vptr?
class A {
public:
int a;
virtual void v();
};
class B {
public:
int b;
virtual void w();
};
class C : public A, public B {
public:
int c;
virtual void x();
};
Run Code Online (Sandbox Code Playgroud)
C的大小是20 ........
似乎在这种情况下,两个vptrs在布局中......这是怎么发生的?我认为两个vptrs一个用于A类,另一个用于B类....所以没有vptr用于C类的虚函数?
我的问题是,关于继承中vptrs数量的规则是什么?
2)虚拟继承
class A {
public:
int a;
virtual void v();
};
class B: virtual …Run Code Online (Sandbox Code Playgroud) 假设我有A一个带有虚函数的类F():
class A
{
virtual void F()
{
// Do something
};
};
Run Code Online (Sandbox Code Playgroud)
我有另一个B继承A和重新定义的 类F():
class B : A
{
void F()
{
// Do something
};
};
Run Code Online (Sandbox Code Playgroud)
还有一个不同的类C,它也继承了A但是覆盖 F():
class C : A
{
void F() override
{
// Do something
};
};
Run Code Online (Sandbox Code Playgroud)
F()课程B和有C什么区别?
我一直在与我的同事讨论是否使用virtual关键字为重写方法添加前缀,或者仅在原始基类中添加前缀.
我倾向于使用virtual关键字为所有虚拟方法(即涉及vtable查找的方法)添加前缀.我的理由是三重的:
鉴于C++缺少override关键字,virtual关键字的存在至少会通知您该方法涉及查找,理论上可以通过进一步的特化来覆盖,或者可以通过指向更高基类的指针来调用.
始终使用这种风格意味着,当你没有virtual关键字看到(在我们的代码至少)的方法,你可以初步认为它既不是从基础衍生也不专门的子类.
如果,通过一些错误,虚拟从IFoo中删除,所有子节点仍将起作用(CFooSpecialization :: DoBar仍会覆盖CFooBase :: DoBar,而不是简单地隐藏它).
正如我所理解的那样,反对这种做法的论点是,"但这种方法不是虚拟的"(我认为这种方法无效,并且来自对虚拟性的误解),并且"当我看到虚拟关键字时,我希望意味着有人从中衍生出来,然后去寻找它们."
假设的类可以分布在几个文件中,并且有几个专门化.
class IFoo {
public:
virtual void DoBar() = 0;
void DoBaz();
};
class CFooBase : public IFoo {
public:
virtual void DoBar(); // Default implementation
void DoZap();
};
class CFooSpecialization : public CFooBase {
public:
virtual void DoBar(); // Specialized implementation
};
Run Code Online (Sandbox Code Playgroud)
从风格上讲,你会从两个派生类中删除虚拟关键字吗?如果是这样,为什么?Stack Overflow的想法是什么?
n3797说:
§7.1.6.4/14:
使用占位符类型的返回类型声明的函数不应是虚拟的(10.3).
因此,以下程序格式错误:
struct s
{
virtual auto foo()
{
}
};
Run Code Online (Sandbox Code Playgroud)
虚拟
允许对虚函数进行返回类型推导是可能的,但这会使重写检查和vtable布局复杂化,因此似乎最好禁止这种情况.
任何人都可以提供进一步的理由或给出一个与上述引用一致的好(代码)示例吗?
什么时候编译器创建一个虚函数表?
1)当类包含至少一个虚函数时.
要么
2)当直接基类包含至少一个虚函数时.
要么
3)当层次结构的任何级别的任何父类包含至少一个虚函数时.
与此相关的问题:是否可以放弃C++层次结构中的动态调度?
例如,考虑以下示例.
#include <iostream>
using namespace std;
class A {
public:
virtual void f();
};
class B: public A {
public:
void f();
};
class C: public B {
public:
void f();
};
Run Code Online (Sandbox Code Playgroud)
哪些类将包含V表?
既然B没有将f()声明为虚拟,那么C类是否会获得动态多态性?
为什么我在谈论子类化/继承时有时会在C++示例中看到,基类有虚拟关键字,有时被覆盖的函数也有虚拟关键字,为什么有时需要向子类添加虚拟关键字?例如:
class Base
{
Base(){};
virtual void f()
......
}
};
class Sub : public Base
{
Sub(){};
virtual void f()
...new impl of f() ...
}
};
Run Code Online (Sandbox Code Playgroud) 在玩实现虚拟赋值运算符的过程中,我以一种有趣的行为结束了.它不是编译器故障,因为g ++ 4.1,4.3和VS 2005共享相同的行为.
基本上,虚拟运算符=与实际执行的代码相比,其行为与任何其他虚拟函数不同.
struct Base {
virtual Base& f( Base const & ) {
std::cout << "Base::f(Base const &)" << std::endl;
return *this;
}
virtual Base& operator=( Base const & ) {
std::cout << "Base::operator=(Base const &)" << std::endl;
return *this;
}
};
struct Derived : public Base {
virtual Base& f( Base const & ) {
std::cout << "Derived::f(Base const &)" << std::endl;
return *this;
}
virtual Base& operator=( Base const & ) {
std::cout << "Derived::operator=( …Run Code Online (Sandbox Code Playgroud) 在我的工作场所(仅限PHP),我们有一个用于数据库抽象的基类.如果要将新数据库表添加到基础层,则必须创建此基类的子类,并重写某些方法以定义使用此表的各个行为.正常行为应该保持不变.
现在我在我们公司看到了许多新的程序员,他们只是覆盖了默认行为的方法.有些人很擅长放入所有默认行为,只是在他们喜欢的地方添加个别内容,其他人则试图使用基类及其继承者.
我第一个想到解决这个问题的想法是考虑应该通过继承类来覆盖的抽象方法.但是除了反对抽象方法的其他论据之外,"抽象"只是没有说明为什么基类不能被它自己使用以及为什么应该覆盖这些函数.
经过一些谷歌搜索后,我没有找到一个很好的答案在PHP中实现"真正的"虚拟功能(只是有一个虚拟功能,几乎杀死了具体实现的所有希望).
那么,你会对这件事做些什么呢?
考虑以下代码(它有点长,但希望你可以遵循):
class A
{
}
class B : A
{
}
class C
{
public virtual void Foo(B b)
{
Console.WriteLine("base.Foo(B)");
}
}
class D: C
{
public override void Foo(B b)
{
Console.WriteLine("Foo(B)");
}
public void Foo(A a)
{
Console.WriteLine("Foo(A)");
}
}
class Program
{
public static void Main()
{
B b = new B();
D d = new D ();
d.Foo(b);
}
}
Run Code Online (Sandbox Code Playgroud)
如果你认为这个程序的输出是"Foo(B)"那么你和我在同一条船上:完全错了!事实上,它输出"Foo(A)"
如果我从C类中删除虚方法,那么它按预期工作:"Foo(B)"是输出.
为什么编译器选择带有Awhen 的版本B是派生得更多的类?
c++ ×8
inheritance ×2
overriding ×2
polymorphism ×2
vtable ×2
auto ×1
c# ×1
c++11 ×1
c++14 ×1
coding-style ×1
methods ×1
objectsize ×1
oop ×1
php ×1
private ×1
virtual ×1