• QT4 原生c++ 1.2 派生类、字符数组开辟空间与销毁


    1 面向对象中两个重要概念

    1 派生类

    派生类:利用继承机制,新的类可以从已有的类中派生。那些用于派生的类称为这些特别派生出的类的“基类”。

    2 虚函数

    虚函数可实现多态性 派生类只调用自己的函数。

    下面来看示例:

    1. class Stack{
    2. public:
    3. virtual void push(char c) = 0; // 虚函数 基类只有定义
    4. virtual char pop() = 0;
    5. };

    基类只有原型的定义

    1. class ArrayStack:public Stack{
    2. char* p;
    3. int maxSize;
    4. int top;
    5. public:
    6. ArrayStack(int s)
    7. {
    8. top = 0;
    9. maxSize = s;
    10. //*****found*****1
    11. //p=_____;
    12. p = new char[s]; //为p申请s个char型空间
    13. }
    14. ~ArrayStack()
    15. {
    16. //*****found*****2
    17. //_____;
    18. delete [] p; //释放指针 new的空间需要释放
    19. }
    20. void push(char c)
    21. {
    22. if(top == maxSize){
    23. cerr<<"Overflow!\n";
    24. return;
    25. }
    26. //*****found*****3
    27. //_____;
    28. p[top] = c; //top为栈顶元素下标 添加的数据放到栈顶
    29. top++;
    30. }
    31. char pop()
    32. {
    33. if(top == 0){
    34. cerr<<"Underflow!\n";
    35. return '\0';
    36. }
    37. top--;
    38. //*****found*****4
    39. //_____;
    40. return p[top];
    41. }
    42. };

    派生类中,对push函数做了具体的实现。

    那么 ,到底何时调用基类的虚函数,何时调用派生类的虚函数呢。这里可以做一个实验。

    1. #include <QtCore/QCoreApplication>
    2. #include <iostream>
    3. using namespace std;
    4. // 类定义
    5. class A
    6. {
    7. public:
    8. virtual void print()
    9. {
    10. cout<<"这是基类A的print函数"<<endl;
    11. }
    12. };
    13. class B : public A
    14. {
    15. public:
    16. virtual void print()
    17. {
    18. cout<<"这是派生类B的print函数"<<endl;
    19. }
    20. };
    21. int main(int argc, char *argv[])
    22. {
    23. QCoreApplication a(argc, argv);
    24. // 定义2个对象
    25. A aa;
    26. B bb;
    27. // 赋值指针
    28. A *p1 = &aa;
    29. A *p2 = &bb;
    30. // 调用成员函数
    31. p1->print();
    32. p2->print();
    33. return a.exec();
    34. }

    简单讲解一下,A是基类,B是派生类,print是虚函数。

    先定义A类的实例aa,在定义B类的实例bb,然后定义基类指针p1和p2,再将aa和bb的地址赋予指针。这时候,p1输出的是A的函数,而p2输出的是B的函数。

    虚函数的理论还是蛮绕的,就不误导观众了,这里最好找教材好好复习一下,这是个重要的知识点。

    2 字符数组的开辟和销毁

    字符数组是本次学习的重点。

    先来看下代码:

    1. #include <QtCore/QCoreApplication>
    2. #include <iostream>
    3. using namespace std;
    4. // 类定义
    5. class Stack{
    6. public:
    7. virtual void push(char c) = 0; // 虚函数可实现多态性 派生类只调用自己的函数
    8. virtual char pop() = 0;
    9. };
    10. class ArrayStack:public Stack{
    11. char* p;
    12. int maxSize;
    13. int top;
    14. public:
    15. ArrayStack(int s){
    16. top = 0;
    17. maxSize = s;
    18. p = new char[s]; //为p申请s个char型空间
    19. }
    20. ~ArrayStack(){
    21. delete [] p; //释放指针 new的空间需要释放
    22. }
    23. void push(char c){
    24. if(top == maxSize){
    25. cerr<<"Overflow!\n";
    26. return;
    27. }
    28. p[top] = c; //top为栈顶元素下标 添加的数据放到栈顶
    29. top++;
    30. }
    31. char pop(){
    32. if(top == 0){
    33. cerr<<"Underflow!\n";
    34. return '\0';
    35. }
    36. top--;
    37. return p[top];
    38. }
    39. };
    40. void f(Stack& sRef){
    41. char ch[] = {'a','b','c'};
    42. cout<<ch[0]<<","<<ch[1]<<","<<ch[2]<<endl;
    43. sRef.push(ch[0]); sRef.push(ch[1]); sRef.push(ch[2]);
    44. cout<<sRef.pop()<<",";
    45. cout<<sRef.pop()<<",";
    46. cout<<sRef.pop()<<endl;
    47. }
    48. int main(int argc, char *argv[])
    49. {
    50. QCoreApplication a(argc, argv);
    51. ArrayStack as(10);
    52. f(as);
    53. return a.exec();
    54. }

    输出结果为

    先来分析下类结构:

    基类Stack派生类ArrayStack
    char* p;
    int maxSize;
    int top;
        virtual void push(char c) = 0; 
        virtual char pop() = 0;

    ArrayStack(int s);

    ~ArrayStack();

    void push(char c);

    char pop();

    基类实现了2个虚函数,1个是进栈push,1个是出栈pop。都是空的。

    派生类实现了4个函数,分别是构造函数,析构函数,进栈push和出栈pop。

    下面来看下main函数的逻辑

    1. 声明ArrayStack的对象as(10),这里要调用构造函数。
    2. 构造函数里,令top为0,maxSize为10,p开辟长度为10的字符数组变量
    3. 回到main,执行f函数,其形参是as。这里注意函数里是Stack类型,是基类。
    4. 在f函数里,as被传进来。声明了ch字符数组,其3个元素为a,b,c。首先cout这3个元素。控制台显示a,b,c。
    5. 对as执行push操作,进入push环节。这里也只能执行派生类的函数了。
    6. ch[0]是a,a进入push函数后,先做判断top == maxSize,这里目前是0==10所以否掉,执行p[top] = c;就是p[0]='a'。随后top自加变为1。
    7. 跳出push后,又来第2个push,变量是ch[1]就是b。继续。1==10不成立,所以p[1]='b' top=2。
    8. 再次push,这里判断2==3不成立,所以p[2]='c',top=3。
    9. 整理一下3次push的操作,ArrayStack对象as的p变量的前3个元素依次被赋予a,b,c三个字符。后面空着的8个元素还是空的。
    10. 下面执行pop操作。进入pop后,top=3,3==0不成立,跳过if,top变2,p[2]被返回,就是c。之后cout就是打印c
    11. 继续pop,top=2,2==0不成立,跳过if,top变1,p[1]=b被返回cout打印。
    12. 继续pop,top=1,1==0不成立,跳过if,top=0,p[0]=a被返回打印。
    13. f函数被执行完毕。返回main函数
    14. 执行完毕。程序退出,开始执行析构函数。
    15. 销毁p空间。

    分析上述过程,p数组其实占用内存空间是固定的10个。pop后,也没有销毁。只有在最后析构函数中才被销毁。

    看来 使用char存储字符不是很方便,比如要执行字符串拼接等操作,可能还是需要string类型更好。

     

  • 相关阅读:
    vue源码学习(2)- Vue初始化过程
    机器学习模型与backtrader框架整合
    学会这几个PPT制作技巧,让同事对你刮目相看
    细解“微服务”架构体系——SpringCloud Alibaba!
    【机器人学导论(第四版)】1-绪论
    【Spring Cloud】服务容错中间件Sentinel进阶——五大规则
    详细刨析Linux权限。包含权限的概念、权限的修改、粘滞位等等。
    lower_bound()与upper_bound()
    【面试算法——动态规划 20】最长公共子序列&& 不相交的线
    pyclipper和ClipperLib操作多边型
  • 原文地址:https://blog.csdn.net/zjjsd195/article/details/125607480