C++面向对象编程的三大特性:封装,继承,多态。
1.封装:隐藏对象的属性和实现细节,只对外开放接口。调用者只需关心如何使用接口,通过接口获得想要的结构。
函数也是封装的一种形式:函数执行的细节调用者不用关心---调用者可以调用一个函数,但是不能访问函数内部执行的语句或变量。
C++类的封装相由访问限定符private,protect,public实现
访问限定符的实现是由编译器实现,数据在内存中的存放没有限制。
例:
#include <QCoreApplication>
class A
{
public:
void PublicFunc();
int publicA;
private:
void PrivateFuncA();
int privateA;
};
void A::PublicFunc()
{
}
void A::PrivateFuncA()
{
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
A mA;
//能正常调用
mA.PublicFunc();
mA.publicA = 0;
//类A的私有函数,只有A才能调用
//mA.PrivateFuncA();
//mA.privateA = 1;
return a.exec();
}
2.继承:可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
继承概念的实现方式有三类:实现继承、接口继承和可视继承。
1. 实现继承是指使用基类的属性和方法而无需额外编码的能力;
2. 接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力;
3. 可视继承是指子窗体(类)使用基窗体(类)的外观和实现代码的能力。
3.多态:实现了一个函数名可以有多种作用,分为静态多态和动态多态
静态多态:通过函数重载实现,具体调用哪个函数在编译时确定。
动态多态:通过虚函数(在函数名前面加上virtual关键字)实现(在有类的继承发生的情况下),运行时确定。虚函数主要是通过虚函数表实现。
虚函数表:每一个类都会生成一个虚函数表,表中存储的是每一个虚函数的地址。类的每一个对象都包含一个虚指针(就是一个指针,此指针存在于对象实例地址的最前面,保证虚函数表有最高的性能),这个虚指针指向虚函数表。同一个类的所有不同实例都是用的相同的一个虚函数表(自己还没有验证过),对象不包含虚函数表,类才包含虚函数表,对象只有虚指针,派生类会生成一个兼容基类的虚函数表。
C++11的新特性:(https://xie.infoq.cn/article/0c68359d19103ca2009006070)
auto关键字,自动类型推导。在编译阶段由编译器自动推导
auto i = 10; //编译器根据10为int变量,在编译阶段自动将auto替换为int
decltype关键字,自动类型推导
使用auto定义变量时,要求必须初始化,decltype不用
decltype(Func) i; //根据函数Func的返回值自动确定 i 的类型,要求Func的返回值不能为void
范围for循环
int main()
{
char arc[] = "http://c.biancheng.net/cplus/11/";
//for循环遍历普通数组
for (char ch : arc)
{
cout << ch;
}
cout << '!' << endl;
vector<char>myvector(arc, arc + 23);
//for循环遍历 vector 容器
for (auto ch : myvector)
{
cout << ch;
}
cout << '!';
return 0;
}
override和final关键字
/*如果不使用override,当你手一抖,将foo()写成了f00()会怎么样呢?结果是编译器并不会报错,因为它并不知道你的目的是重写虚函数,而是把它当成了新的函数。如果这个虚函数很重要的话,那就会对整个程序不利。 所以,override的作用就出来了,它指定了子类的这个虚函数是重写的父类的,如果你名字不小心打错了的话,编译器是不会编译通过的:*/
class A { virtual void foo(); } class B :public A { void foo(); //OK virtual foo(); // OK void foo() override; //OK } class A { virtual void foo(); }; class B :A { virtual void f00(); //OK virtual void f0o()override; //Error };
/*当不希望某个类被继承,或不希望某个虚函数被重写,可以在类名和虚函数后添加final关键字,添加final关键字后被继承或重写,编译器会报错。例子如下:*/ class Base { virtual void foo(); }; class A : Base { void foo() final; // foo 被override并且是最后一个override,在其子类中不可以重写 void bar() final; // Error: 父类中没有 bar虚函数可以被重写或final }; class B final : A // 指明B是不可以被继承的 { void foo() override; // Error: 在A中已经被final了 }; class C : B // Error: B is final { };
空指针常量nullptr,线程支持,智能指针等。