C++知识点集锦(类中的多态、虚函数、vtable、vptr、static对象等)

Visual Studio的使用

1. 右键速览定义

2. visual studio 项目架构
参考
- 解决方案 - 一个个project - cpp/ .h
解决方案
如上图,一个解决方案下有一个sln文件及其包含的两个项目的文件夹。而每一个项目除了其所包含的.cpp .h源码文件外,其余的就两个projcetName.vcxproj是上面提到的project文件;另一个就是projectName.vcxproj.filters 文件,这个文件保存了在项目中的源代码文件文件的分组情况,例如常见的头文件,源文件,也可以添加自定义的分组,这些信息就保存在该文件中。有了这些了解以后,将项目托管到git上,就知道了那些文件应该push,那些文件应该ignore了。

3. 注释
ctrl+c 添加注释
ctrl+u 去除注释

注意,如果把整行选中,出来的注释是 // 形式的
如果选中的行前面有空格,那么注释是 /* */形式的


C++(面向对象)三大特性

封装、继承、多态

封装

封装可以隐藏实现细节,使得代码模块化
封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面。

数据抽象(abstraction)
只向外界提供关键信息,并隐藏其后台的实现细节,即只表现必要的信息而不呈现细节。

抽象类(abstract class)
类中至少有一个函数被声明为纯虚函数/纯虚函数是通过在声明中使用=0来指定。
抽象类不能被实例化。


多态

多态指的是父类类型的指针指向其子类对象,可以调用子类中被重写(override)的方法

C++中,实现多态有以下方法:虚函数抽象类(纯虚函数,即 virtual 函数名()=0),重写(override)模板(重载和多态无关)。

重载(overload)与重写(override)的区别
成员函数被重载的特征:
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不同;
(4)virtual 关键字可有可无。

重写是指派生类函数覆盖基类函数,特征是:
(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有virtual 关键字。

例子:(通过虚函数实现多态)

class A
{
public:
    A(){}
    virtual void foo()
    {
        cout<<"This is A."<<endl;
    }
};
 
class B: public A
{
public:
    B(){}
    void foo()
    {
        cout<<"This is B."<<endl;
    }
};
 
int main(int argc, char *argv[])
{
    A *a = new B();
    a->foo();
    if(a != NULL)
    delete a;
    return 0;
}

继承

通过继承机制,可以利用已有的数据类型来定义新的数据类型。所定义的新的数据类型不仅拥有新定义的成员,而且还同时拥有旧的成员。我们称已存在的用来派生新类的类为基类,又称为父类。由已存在的类派生出的新类称为派生类,又称为子类。

公有继承、私有继承、保护继承

private:可以被自己访问,但是不能被子类访问

protected:可以被自己和自己的子类访问,但是自己不能访问其他实例化对象的 protected

public:都可以访问


动态联编、静态联编

动态联编: 在运行的时候,自动判断指向的成员函数
静态联编:在编译阶段,确定指向的成员函数是指针类型的成员函数

虚函数

虚函数的定义要遵循以下重要规则:

1.如果虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数不同,或者是返回类型不同,那么即使加上了virtual关键字,也是不会进行滞后联编的。

2.只有类的成员函数才能说明为虚函数,因为虚函数仅适合用于有继承关系的类对象,所以普通函数不能说明为虚函数。

3.静态成员函数不能是虚函数,因为静态成员函数的特点是不受限制于某个对象。

4.内联(inline)函数不能是虚函数,因为内联函数不能在运行中动态确定位置。即使虚函数在类的内部定义定义,但是在编译的时候系统仍然将它看做是非内联的。

5.构造函数不能是虚函数,因为构造的时候,对象还是一片未定型的空间,只有构造完成后,对象才是具体类的实例。

6.析构函数可以是虚函数,而且通常声名为虚函数。

static类数据成员/成员函数

两者都不能用this指针指向他们

  • 类数据成员
    static类数据成员独立于一切类对象存在。
    static不会像普通类数据成员一样每一个类对象都有一份,全部类对象是共享一个static类成员的。
    static类对象必须要在类外进行初始化
class Text{
	public:
	static int count;
} ;
int Text::count=0; //必须初始化
  • 类成员函数
    类成员函数里不能访问非static类成员

虚函数表vtable以及vptr

如果一个类包含了虚函数,那么在创建对象时会额外增加一张表,表中的每一项都是虚函数的入口地址,虚函数按照创建的优先顺序排列。这张表就是虚函数表,也称为 vtable。
可以认为虚函数表是一个数组。 为了把对象和虚函数表关联起来,编译器会在对象中安插一个指针vptr(在对象对应的内存空间的开头),指向虚函数表的起始位置。
例子:

class A{
protected:
	int a1;
	int a2;
public:
	virtual void display(){
		cout<<"A::display()"<<endl;
	}
	virtual void clone(){ 
		cout<<"A::clone()"<<endl;
	};
};

class B: public A{
protected:
	int b;
public:
	virtual void display(){
		cout<<"B::display()"<<endl;
	}
	virtual void init(){ 
		cout<<"B::init()"<<endl;
	}
};

class C: public B{
protected:
	int c;
	
public:
	virtual void display(){
	cout<<"C::display()"<<endl;
	}
	virtual void execute(){ 
	cout<<"C::execute()"<<endl;
	}
};

各个类的内存分布如下所示:
虚函数表

Operator

  1. c++ 中的operator()有两大主要作用:
    Overloading------重载()操作符;
    Casting------实现对象类型转化。

STL

参考文章

queue

queue的实现:底层使用链表(linked list)实现


vector

原理:内部使用array实现,所以要更改大小为taks linear time

  • 头文件
#include<vector>
  • vector的初始化
vector<vector<int>> v(n, vector<int>(n, 0))

优先队列

<queue>中,有priority_queue

priority_queue<int, vector,greater> big;
big.top() 访问的是最小元素
big.pop() 弹出来的耶是最小的元素

优先队列就是根据一定的顺序对进入队列的数进行排序,是用堆实现的。

C++ 零散知识点

1. 浮点数精度
float的十进制的精度为为6~7位
double精度最高位16位,一定可以保证15位

2. namespace
namespace参考

3. _declspec(dllexport)与_declspec(dllimport)
_declspec(dllexport)与_declspec(dllimport)是相互呼应,只有在DLL内部用dllexport作了声明,才能在外部函数中用dllimport导入相关代码

4. 运算符重载

classA& operator=(...){

}

5. math.h
pow
fabs

6. 智能指针

自己管理内存,不用 delete了
c++智能指针详解

智能指针原理:引入控制块,对引用计数

shared_ptr
unique_ptr:仅有一个指针指向一块内存区域
weak_ptr:辅助shared_ptr

7. 头文件
包含所有头文件的头文件

#include<bits/stdc++.h>

8. delete 和 delete[]
如果数据类型有析构函数,则需要使用delete []。
单单使用delete 则只调用了数组里面第一个元素的构造函数。

或者说
new -> delete
new [] -> delte[]



内联函数

内联函数详解

利:避免了指令的来回跳转,加快程序执行速度

弊:代码被多次复制,增加了代码量,占用更多的内存空间


头文件

cstdio

cstdio是 c++版本的c语言的<stdio.h>,里面的函数如 scanf, print, fopen等

注意 scanf一个字符(%c)时,前面不能有空格,不然要先在前面加一个%c,以达到吸收空格的目的

字符串操作

  1. to_string(char)是错误的,因为char底层是int,所以to_string后会转换成ASCII码

substr

string.substr(start_pos, length)
比如:

s.substr(i, j-i+1); // 取[i,j]里的字符串

string和int相互转换

C++中将string 类型与int类型的相互转换

C++ 11的新特性

  1. auto

  2. 列表初始化

  3. decltype:求表达式的类型

  4. nullptr

  5. 右值引用,move(把左值转换成右值)

  6. Lambda表达式

  7. 智能指针

  8. 正则表达式

  9. 在STL里增加了无序容器

  10. for循环访问容器里的元素

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值