C++面试考点:类(class)
1、类的定义
C++中的类提供了面向对象编程、继承与多态的机制。其构成包括成员(各种自定义数据)、行为(定义的函数操作)、封装(private、public、protected)。核心是了解类的继承机制,以及各种封装的使用方式和使用范围。以及理解构造函数和析构函数。
要注意类和struct的区别。在C++中,类成员默认属性为private,而struct中默认属性为public。一个类的基本定义如下:
其中private关键字会使得私有成员或函数只能由当前类访问。
protected关键字会使得其成员或函数只能由该类或派生(继承)类访问。
public关键字会使得成员或函数可以被直接访问。
2、类的访问控制关键字
public:该成员对所有人都是可见的,类的外部可以自由访问。
protected:只能在类的内部访问,外部或子类都不能访问。(好像friend友类可以访问)
protected:在类内部和派生类中可以访问,但类外部不能访问。
比如如下例子,注意观察不同属性成员的操作方式:
#include<bits/stdc++.h>
using namespace std;class Teacher{
public:string name;virtual void setName(string _name){name = _name;}void print_homeAddr(){cout<<homeAddr;}protected:string homeAddr = "school";private:int salary = 2000;
};int main() {Teacher A;A.setName("A"); //public 可以外部直接访问cout<<A.name;//错误:cout<<A.homeAddr; //protected外部不可以访问
//错误:cout<<A.salary; //private 外部不可以访问A.print_homeAddr(); //可以访问,因为print_homeAddr是public属性, 在类中可以访问protected成员变量。return 0;
}
3、类的继承
继承允许一个类(子类/派生类)继承另一个(父类/基类)的成员变量和成员函数,从而实现代码复用。类的继承语法如下:
要注意类和struct中继承的区别,类默认继承方式为private,struct的默认继承方式为public。继承的时候,如果原来属性为public,继承方式为private,那么所有成员和函数的属性都会变成private。 但反过来不行,即原来是private,用public继承,继承后类的成员属性仍是private。
继承的类中可以定义与父类同名的变量或函数。此时要注意对变量和没有virtual关键字函数的重定义称之为”隐藏“(hiding),对具有virtual关键字函数的定义称之为”重写“(override)。
#include <iostream>
using namespace std;class Base {
public:int value = 10;
};class Derived : public Base {
public:int value = 20; // 和 Base::value 同名
};int main() {Derived d;cout << "Derived::value = " << d.value << endl; // 输出 20cout << "Base::value = " << d.Base::value << endl; // 输出 10return 0;
}
4、 继承与多态相关关键字
virtual:声明虚函数,支持运行时多态。
override:C++11引入,标识函数是重写基类的虚函数,更安全的实现多态。
final:防止类被继承或函数被子类重写。
virtual ~:虚析构函数,确保通过基类指针删除子类对象时能正确释放资源,
目前被问到的只有virtual,虚函数就是指继承的子类可以通过重写的方式来覆盖父类的函数,从而实现自己所需要的功能。 简单来说虚函数通过每个类的虚函数表(vtable)和虚函数表指针(vptr)来实现重写后的函数位置的记录。如果子类重写了父类的virtual函数,那么就会产生自己的虚函数表,并记录更新对应函数为重写后的地址。从而在调用函数时,通过虚地址表指针(vptr)来执行对应的函数。
5、析构函数与虚析构函数
析构函数的定义方式如下所示(不能带参数,没有返回值)。自动调用时机包括:局部对象作用域结束时、动态对象(new创建的)用delete删除时。析构函数的调用顺序是先调用派生类析构函数,再调用基类析构函数(从子到父)。
class MyClass {
public:~MyClass(); // 析构函数,无返回值、无参数
};
虚析构函数的必要性:虚析构函数就是指在析构函数前加上virtual关键字,标识可以被子类重写。这么做是很有必要的。如果没有virtual关键字,子类在释放时只会调用基类的析构函数,而不会调用自己的析构函数,从而造成资源浪费与泄露。