继承
class next:public Base{
...
};final
禁用继承
class Base final{
...
};explicit
用于修饰类的构造函数,表示该构造函数必须为显示的。
类构造函数只有一个参数时,可隐式构造:CString s = 10编译器会自动调用CString s(10)
隐式构造容易出错
上下转型
Base base = myImplement;
Base &base = myImplement;不加引用会导致数据截断。
通常不建议向下转型,若需要使用则通过static_cast<Implement *>(base)或者dynamic_cast<Implement *>(base)。
运行时工具
RTTI运行时类型信息
#include<typeifo>
class Animal{public: virtual ~Animal() = default};
class Dog: public Animal{};
class Cat: public Animal{};
void speak(const Animal & animal){
if(typeid(animal)==typeid(Dog)){...}
if(typeid(animal)==typeid(Cat)){...}
}虚函数
虚函数是C++中实现多态的一种机制。当基类中的某个函数被声明为虚函数时,其派生类中的同名函数自动成为虚函数,无论是否使用virtual关键字。
c++中的虚函数主要作用是允许在派生类中重新定义基类的函数,以便实现特定的行为。通过基类指针或引用调用虚函数时,能够根据实际对象的类型来决定调用哪个函数,从而实现运行时多态。
如果在基类中没有定义虚函数,派生类可以调用基类中的非虚函数。即使基类中的函数没有被定义为虚函数,派生类仍然可以继承并调用这些函数。在这种情况下,派生类对基类函数的调用是通过静态绑定进行的,即在编译时就已经确定了要调用的函数。
- 继承:派生类继承基类的所有非私有成员函数,包括非虚函数。因此,派生类对象可以调用这些继承来的非虚函数。
- 静态绑定:对于非虚函数,调用哪个函数是在编译时确定的,基于对象的静态类型(即声明时的类型)而不是动态类型(即实际对象的类型)。
- 覆盖与重载:如果派生类定义了一个与基类中非虚函数同名但参数列表不同的函数,这被称为重载,而不是覆盖。调用哪个函数将基于函数的参数列表和对象的静态类型。
- 访问控制:派生类调用基类非虚函数的权限取决于基类中该函数的访问级别(如public、protected或private)。如果基类函数是私有的,派生类将无法直接调用它。
需要注意的是,如果希望在派生类中修改基类函数的行为,并且希望这种修改在通过基类指针或引用调用时生效(即实现多态),那么应该将基类中的相应函数声明为虚函数。非虚函数的调用不会实现多态行为。
虚基类
虚基类是C++中用于解决多继承时可能出现的二义性问题的一种机制。当某个类在多条继承路径上被多次继承时,如果不使用虚基类,那么这个类的成员变量和成员函数可能会在派生类中存在多个副本,导致二义性和资源浪费。 概念:
虚继承:虚基类是通过虚继承来实现的。在声明继承关系时,使用
virtual关键字来指定基类为虚基类。共享副本:通过虚继承,无论虚基类在继承层次中出现了多少次,派生类中都只包含虚基类的一个共享副本。
虚基类表:为了实现这种共享,编译器会为每个包含虚基类的对象添加一个虚基类表,用于记录虚基类成员的偏移量。 用法:
声明虚基类:在继承时使用
virtual关键字。class A { /* ... */ }; class B : virtual public A { /* ... */ }; class C : virtual public A { /* ... */ }; class D : public B, public C { /* ... */ };在这个例子中,
A是B和C的虚基类,D通过B和C间接继承了A,但A的成员在D中只有一个副本。构造函数调用:虚基类的构造函数由最派生的类负责调用,而不是由直接继承的子类调用。
class A { public: A() { /* ... */ } }; class B : virtual public A { public: B() { /* ... */ } // 不调用A的构造函数 }; class C : virtual public A { public: C() { /* ... */ } // 不调用A的构造函数 }; class D : public B, public C { public: D() : A(), B(), C() { /* ... */ } // 由D负责调用A的构造函数 };避免二义性:使用虚基类可以避免在多继承情况下对基类成员的访问产生二义性。
D d; d.someMemberOfA; // 无二义性,因为A的成员在D中只有一个副本注意事项:
- 虚基类主要解决的是多继承中的二义性问题,并不是所有多继承场景都需要使用虚基类。
- 虚基类的构造函数由最派生的类负责调用,因此需要确保最派生的类能够访问到虚基类的构造函数。
- 虚继承会引入一些额外的开销,如虚基类表,因此在使用时应权衡其利弊。 通过合理使用虚基类,可以有效地管理多继承关系,避免潜在的二义性和资源浪费问题。

