必须通过列表来进行初始化
以下成员必须通过列表来初始化而不能在构造函数体内初始化。
- const修饰的类成员变量:必须通过初始化列表初始化并且一旦初始化不可改变
- 引用变量成员:必须在创建时绑定到一个对象
- 带有引用的类变量
- 类成员是其他类并且该类没有默认的构造函数:通过列表进行初始化
- 父类没有默认的构造函数
不能声明为虚函数的
在C++中,并非所有函数类型都可以被声明为虚函数。以下是不能被声明为虚函数的函数类型的详细说明:
-
构造函数(Constructors)
构造函数不能被声明为虚函数。这是因为虚函数机制依赖于虚表(vtable),而虚表是在对象构造完成后才完全初始化的。在构造函数执行时,对象尚未完全创建,因此无法通过虚函数机制进行动态分派。此外,构造函数的目的是初始化对象,其调用顺序由语言规则严格定义,不需要动态多态性。
-
静态成员函数(Static Member Functions)
静态成员函数不能被声明为虚函数。虚函数的动态分派依赖于对象的实例,而静态成员函数属于类本身,与具体对象无关。因此,静态成员函数没有“this”指针,无法通过虚表进行动态绑定。
-
全局函数(Non-Member Functions)或友元函数(Friend Functions)
全局函数和友元函数不属于类的成员函数,因此无法被声明为虚函数。虚函数机制仅适用于类的成员函数,以便实现运行时多态性。
-
内联函数(Inline Functions)
内联函数原则上可以被声明为虚函数,但是虚函数表示多态时不能进行内联,但需要注意其实际行为。如果内联函数被声明为虚函数,并且在编译时调用点能够确定具体的函数版本(例如通过对象而非指针或引用调用),编译器可能会内联优化而忽略虚函数机制。然而,通过指针或引用调用时,虚函数的动态分派仍然会生效。因此,虽然内联函数可以是虚函数,但内联和虚函数的结合可能导致行为上的复杂性。
关于const同名字函数的调用优先级问题
在 C++ 中,当一个类中有同名函数(如 f() 和 f() const)时,编译器会根据调用者的上下文(特别是对象的 const 性)来决定调用哪个版本。这种选择与以下因素有关:
- 指针的 const 性:
- p 的类型是 A*,即一个指向非 const A 的指针。
- 这意味着通过 p 可以调用非 const 成员函数,也可以调用 const 成员函数(因为非 const 对象隐式地也可以被当作 const 对象处理)。
- 重载解析规则:
- 当有多个同名函数(如 void f() 和 void f() const)时,C++ 编译器会选择“最匹配”的版本。
- 对于非 const 对象(或非 const 指针/引用),编译器优先选择非 const 版本的函数,因为它不需要额外的 const 转换。
- 只有当对象被显式声明为 const(或通过 const 指针/引用访问)时,才会调用 const 版本。
- 虚函数的动态绑定:
- p 指向的是一个 B 对象,且 A::f() 是虚函数,因此调用时会动态绑定到 B::f()。
- 但这里的“动态绑定”只决定调用哪个类的实现(A 还是 B),而是否选择 const 版本是由调用时的静态类型(A*)和上下文决定的。
using namespace std;
class A{
public:
virtual void f() { cout << "A::f() "; }
void f() const { cout << "A::f() const "; }
};
class B : public A {
public:
void f() { cout << "B::f() "; }
void f() const { cout << "B::f() const "; }
};
void g(const A* a) {
a->f();
}
int main(int argc, char *argv[]) {
A* p = new B();
p->f();//这里调用时候优先被调用非const的版本
g(p);//const参数传入,只能调用const版本
delete(p);
return 0;
}
关于指针和引用的区别
1) 引用必须被初始化,指针不必。
2) 引用初始化以后不能被改变,指针可以改变所指的对象。
3) 不存在指向空值的引用,但是存在指向空值的指针。

被折叠的 条评论
为什么被折叠?



