IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 关于c++ 中的智能指针和多态的反思 -> 正文阅读

[C++知识库]关于c++ 中的智能指针和多态的反思

忙碌的一天,不停的思考,在忙碌的工作之余,还是要对一天的代码做下总结,毕竟一些方面如果不记下来可能就忘掉了,我的文笔不是很好,所以用例子代替自己的心得吧,还是跟以前一样希望技术越来越好,毕竟每次接触到新的东西都会非常非常开心。

好了,记下我的例子

1.第一个例子:unique_ptr和shared_ptr一个坑

unique_ptr需要检测静态类的大小,但是shared_ptr不需要

思考第一个坑,如果我们在shared_ptr中,声明了一个unique_ptr,这时候能运行吗

代码案例

#include <iostream>
#include <memory>
#include <functional>
class B;
class A {

public:

  A() {

  }

  void hello() {
    std::cout << "hello" << std::endl;
  }
  

private:
  std::unique_ptr<B> data;
  
};

int main(int argc, char **argv) {
  std::shared_ptr<A> a = std::make_unique<A>();
  return 0;
}

2.第二个例子

关于多态,c++的多态不用多说了,也是重点之中的重点,会了多态能让我们代码的可扩展性更高,总结以下几个点

1.多态构造函数顺序从父类到子类,析构顺序从子类到父类(基础)

案例展示

#include <iostream>
#include <functional>

class A{
public:
A() {
  std::cout << "A" << std::endl;
}

~A() {
std::cout << "~A" << std::endl;
}
};

class B {
public:
B() {
std::cout << "B" << std::endl;
}

~B() {
std::cout << "~B" << std::endl;
}
};

class C :public B, public A {
public:
C() {
std::cout << "C" << std::endl;
}

~C() {
std::cout << "~C" << std::endl;
}
};

int main() {
  C c;
  return 0;
}

输出结果:

B
A
C
~C
~A
~B

2.涉及到多态析构函数 一定要加上virtual,不加十分容易内存泄漏(这是个坑,一定要注意),尤其是delete动态绑定,不加就内存泄漏了

动态绑定进行delete,会造成内存泄漏,案例展示:

#include <iostream>
#include <functional>

class A{
public:
A() {
  std::cout << "A" << std::endl;
}

~A() {
std::cout << "~A" << std::endl;
}
};

class B {
public:
B() {
std::cout << "B" << std::endl;
}

~B() {
std::cout << "~B" << std::endl;
}
};

class C :public B, public A {
public:
C() {
std::cout << "C" << std::endl;
}

~C() {
std::cout << "~C" << std::endl;
}
};

int main() {
  B* b = new C();
  delete b;
  return 0;
}

输出结果:

B
A
C
~B

发现只运行了B的析构A和C没运行,这时候如果析构里有内存释放,这时候不触发会出现很危险的内存泄漏

如何防止这种问题的发生?办法当然有析构函数虚函数化

#include <iostream>
#include <functional>

class A{
public:
A() {
  std::cout << "A" << std::endl;
}

virtual ~A() {
std::cout << "~A" << std::endl;
}
};

class B {
public:
B() {
std::cout << "B" << std::endl;
}

virtual ~B() {
std::cout << "~B" << std::endl;
}
};

class C :public B, public A {
public:
C() {
std::cout << "C" << std::endl;
}

~C() {
std::cout << "~C" << std::endl;
}
};

int main() {
  B* b = new C();
  delete b;
  return 0;
}

3.多态如果子类无参数,父类有参数,一定要给父类,初始化一个空的构造函数,因为c++的编译器会自动触发父类的构造函数

加入B和A两个类都有参数了,那么我们一定要给她们一个默认构造函数,否则编译不会通过,正确案例

#include <iostream>
#include <functional>

class A{
public:
A(int a) {
  
}
A() {
  std::cout << "A" << std::endl;
}

virtual ~A() {
std::cout << "~A" << std::endl;
}
};

class B {
public:
B(int a) {

}
B() {
std::cout << "B" << std::endl;
}

virtual ~B() {
std::cout << "~B" << std::endl;
}
};

class C :public B, public A {
public:
C() {
std::cout << "C" << std::endl;
}

~C() {
std::cout << "~C" << std::endl;
}
};

int main() {
  B* b = new C();
  delete b;
  return 0;
}

4.多态如果子类有参数,那么如何调用父类的有参构造函数?

#include <iostream>
#include <functional>

class A{
public:
A(int a) {
  
}
A() {
  std::cout << "A" << std::endl;
}

virtual ~A() {
std::cout << "~A" << std::endl;
}
};

class B {
public:
B(int a) {

}
B() {
std::cout << "B" << std::endl;
}

virtual ~B() {
std::cout << "~B" << std::endl;
}
};

class C :public B, public A {
public:
C(int c) :B(c), A(c){
std::cout << "C" << std::endl;
}

~C() {
std::cout << "~C" << std::endl;
}
};

int main() {
  B* b = new C(1);
  delete b;
  return 0;
}

重点是在这里

C(int c) :B(c), A(c){

不然默认都会调用父类的空构造函数

3.一个规范

谷歌开发者规范明确规定一个参数必须要


class C :public B, public A {
public:
explicit C(int c) :B(c), A(c){
std::cout << "C" << std::endl;
}

~C() {
std::cout << "~C" << std::endl;
}
};

这是为了避免

class C :public B, public A {
public:
C(int c) :B(c), A(c){
std::cout << "C" << std::endl;
}

~C() {
std::cout << "~C" << std::endl;
}
};

int main() {
  C a = 1;
  return 0;
}

这种很容易出问题的操作发生,一个参数构造函数,必须要显示化,避免隐式转换

4.关于inline

这个一直都知道还是写下来吧,很短的函数用inline,编译器编译会自动展开,性能比较好,但是有循环和代码行数比较多的不要展开!

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-19 11:52:27  更:2021-08-19 11:52:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 14:19:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码