【CPP】继承和虚函数

这篇具有很好参考价值的文章主要介绍了【CPP】继承和虚函数。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1- Improve Your Source Code

Suggestions to your Project3

  • Use size_t for mat.cols and mat.rows
  • use memcpy() to copy data. Element assignment has a lower efficiency
  • Use 1D array (float *) nor 2D array (float **) for matrix data
  • Redundant computation in loops
  • Do parameter checking in functions: null pointers, dimension matching in matrix operations, etc
  • Do not bind the create matrix function with file I/O
  • File name : head.h, source1.c, source2.c, source3.c. NO!
  • Good implementation VS good homework

matrix.h

#ifndef _MATRIX_H
#define _MATRIX_H

#include "stdbool.h"  // for bool
#include "stdlib.h"

typedef struct Matrix_{  // use typedef to simplify type name
    size_t rows;   // use size_t,  not int
    size_t cols;   // use size_t, not int
    float * data;
}Matrix;


Matrix * createMat(size_t rows, size_t cols);
bool releaseMat(Matrix * p);
bool add(const Matrix * input1, const Matrix * input2, Matrix *output);

#endif

matrix.c

#include <stdlib.h>
#include <stdio.h>
#include "matrix.h"

// return NULL if failed
Matrix * createMat(size_t rows, size_t cols)
{
    Matrix * p = NULL;
    
    if (rows == 0 || cols == 0)
    {
        fprintf(stderr, "rows and/or cols is 0.\n");  // 错误打印到标准错误输出,可以通过管道把错误信息导到不同的文件
        return NULL;
    }

    // allocate memory
    p = (Matrix *) malloc(sizeof(Matrix));
    if (p == NULL)
    {
        fprintf(stderr, "Failed to allocate memory for a matrix.\n");
        return NULL;
    }

    p->rows = rows;
    p->cols = cols;
    p->data = (float *) malloc(p->rows * p->cols * sizeof(float));

    if (p->data == NULL)
    {
        fprintf(stderr, "Failed to allocate memory for the matrix data. \n");
        free(p);  // Don't forget to free memory here;
        return NULL;
    }

    return p;
}

bool releaseMat(Matrix * p)
{
    // don't forget to check a pointer before using it
    if (!p) return false;

    if (p->data) free(p->data);

    free(p);

    return true;
}

bool add(const Matrix * input1, const Matrix * input2, Matrix * output)
{
    // You must check all parameters carefully first
    // It's important,  and can save a lot of time on debugging
    if (input1 == NULL)
    {
        // use stderr for error messages
        fprintf(stderr, "File %s, Line %d, Function %s(): The 1st parameter is NULL. \n",
        __FILE__, __LINE__, __FUNCTION__);
        return false;
    }
    else if (input1->data == NULL)
    {
        fprintf(stderr, "%s(): The 1st parameter has no valid data. \n", __FUNCTION__);
        return false;
    }

    if (input2 == NULL)
    {
        // use stderr for error messages
        fprintf(stderr, "File %s, Line %d, Function %s(): The 2nd parameter is NULL. \n",
        __FILE__, __LINE__, __FUNCTION__);
        return false;
    }
    else if (input2->data == NULL)
    {
        fprintf(stderr, "%s(): The 2nd parameter has no valid data. \n", __FUNCTION__);
        return false;
    }

    if (output == NULL)
    {
        // use stderr for error messages
        fprintf(stderr, "File %s, Line %d, Function %s(): The 3rd parameter is NULL. \n",
        __FILE__, __LINE__, __FUNCTION__);
        return false;
    }
    else if (output->data == NULL)
    {
        fprintf(stderr, "%s(): The 3rd parameter has no valid data. \n", __FUNCTION__);
        return false;
    }

    if (input1->rows != input2->rows || input2->rows != output->rows || 
        input1->cols != input2->cols || input2->cols != output->cols)
    {
        fprintf(stderr, "The input and the output do not match. They should have the same size. \n");
        fprintf(stderr, "Their sizes are(%zu, %zu), (%zu, %zu) and (%zu, %zu)", 
                input1->rows, input1->cols,
                input2->rows, input2->cols,
                output->rows, output->cols);
        
        return false;
    }

    // version1, the best one
    size_t length = input1->rows * input1->cols;
    const float * p1 = input1->data;
    const float * p2 = input2->data;
    float *p3 = output->data;
    for(size_t i = 0; i<length; i++)
    {
        *(p3++) = *(p1++) + *(p2++);
    }
    
    // version2, better one
    for (size_t r = 0; r < input1->rows; r++)
    {
        // to calculate (col*r) herre, don't put it into the inner loop
        const float *p1 = input1->data + input1->cols * r;
        const float *p2 = input2->data + input2->cols * r;
        float *p3 = output->data + output->cols * r;

        for (size_t c = 0; c < input1->cols; c++)
        {
            *(p3++) = *(p1++) + *(p2++);
        }
    }


    // version3, a bad one
    for(size_t r = 0; r < input1->rows; r++)
    {
        for (size_t c = 0; c < input2->cols; c++)
        {
            output->data[output->cols * r + c] = 
            input1->data[input1->cols * r + c] +
            input2->data[input2->cols * r + c]; 
        }
    }
    return true;
}

main.c

#include <stdio.h>
#include "matrix.h"


int main()
{
    Matrix * matA = createMat(2, 3);
    Matrix * matB = createMat(2, 3);
    Matrix * matC = createMat(2, 3);
    Matrix * matD = createMat(3, 2);
    Matrix * matNULL = NULL;

    //initialization
    // You should have your own method to do it
    matA->data[3] = 2.3f;
    matB->data[3] = 3.1f;


    if( !add(matA, matB, matC))
    {
        fprintf(stderr, "Mayrtix addition failed.");
    }
    else{
        // You can have a metter method to show the results
        printf("result=%f\n", matC->data[3]);
    }

    // more tests
    add(matA, matB, matD);

    add(matNULL, matB, matC);

    return 0;


}
gcc *.c
./a.out
result=5.400000
The input and the output do not match. They should have the same size. 
Their sizes are(2, 3), (2, 3) and (3, 2)File matrix.c, Line 58, Function add(): The 1st parameter is NULL.

2-Derived Class

Inheritance

  • Inherit members (attributes and functions) from one class

(1) Base class (parent)
(2) Derived class (child)

class Base
{
  public:
    int a;
    int b;
};

class Derived: public Base
{
  public:
    int C;
};
  • C++ supports multiple inheritance and multilevel inheritance
    多个继承:
class Derived: public Base1, public Base2
{
  ...
};

Constructors

构造函数在子类中怎么执行

  • To instantiate a derived class object

(1) Allocate memory
(2) Derived constructor is invoked:

[1] Base object is constructed by a base constructor
[2] Member initializer list initializes members
[3] To execute the body of the derived constructor

class Derived: public Base
{
  public:
    int c;
    Derived(int c): Base(c - 2, c - 1), c(c)
    {
      ...
    }
};

Destructors

  • The destructor of the derived class in invoked first
  • Then the destructor of the base class

Example

derived.cpp

#include <iostream>
using namespace std;

class Base
{
  public:
    int a;
    int b;
    Base(int a = 0, int b = 0)
    {
        this->a = a;
        this->b = b;
        cout << "Constructor Base::Base(" << a << ", " << b << ")" << endl;
    }
    ~Base()
    {
        cout << "Destructor Base::~Base()" << endl;
    }
    int product()
    {
        return a * b;
    }
    friend std::ostream & operator<<(std::ostream & os, const Base & obj)
    {
        os << "Base: a = " << obj.a << ", b = " << obj.b;
        return os;
    }
};

class Derived: public Base
{
  public:
    int c;
    Derived(int c): Base(c - 2, c - 1), c(c)
    {
        this->a += 3; //it can be changed after initialization
        cout << "Constructor Derived::Derived(" << c << ")" << endl;
    }
    ~Derived()
    {
        cout << "Destructor Derived::~Derived()" << endl;
    }
    int product()
    {
        return Base::product() * c;
    }
    friend std::ostream & operator<<(std::ostream & os, const Derived & obj)
    {
        // call the friend function in Base class
        os << static_cast<const Base&>(obj) << endl;

        os << "Derived: c = " << obj.c;
        return os;
    }
};

int main()
{
    {
        Base base(1, 2);
        cout << "Product = " << base.product() << endl;
        cout << base << endl;
    }
    cout << "----------------------" << endl;
    {
        Derived derived(5);
        cout << derived << endl;
        cout << "Product = " << derived.product() << endl; 
    }
    return 0;
}

Constructor Base::Base(1, 2)
Product = 2
Base: a = 1, b = 2
Destructor Base::~Base()
----------------------
Constructor Base::Base(3, 4)
Constructor Derived::Derived(5)
Base: a = 6, b = 4
Derived: c = 5
Product = 120
Destructor Derived::~Derived()
Destructor Base::~Base()

3- Access Control

Member Access

  • Public members
    Accessible anywhere
  • Private members
    Only accessible to the members and friends of that class
class Person{
  private:
    int n;  // private member
   
  public:
    // this->n is accessible
    Person() : n(10) {}     // initialization 
    // other.n is accessible
    Person(const Person& other): n(other.n) {}   // Copy constructor
    // this->n is accessible 
    void set(int n) {this->n = n;}
    // this->n and other.n are accessible 
    void set(const Person& other) {this->n = other.n; }
};
  • Protected members

Accessible to the members and friends of that class

class Base
{
  protected:
    int n;
  private:
    void fool(Base& b)
    {
      n++;   // Okay
      b.n++;   // Okay
    }
};

Accessible to the members and friends of the derived class

class Derived : public Base
{
  void foo2(Base& b, Derived& d)
  {
    n++;   // Okay
    this->n++;   // Okay
    b.n++;    // Error
    d.n++;   // Okay
  }
};


// a non-member non-friend function
void compare(Base& b, Derived& d)
{
  b.n++; // Error
  d.n++;  // Error
}

Public Inheritance

  • Public members of the base class

(1) Still be public in the derived class
(2) Accessible anywhere

  • Protected members of the base class

(1) Still be protected in the derived class
(2) Accessible in the derived class only

  • Private members of the base class

(1) Not accessible in the derived class

可以通过父类公有函数去访问

Protected Inheritance

  • Public members and protected members of the base class

(1) Be protected in the derived class
(2) Accessible in the derived class only

  • Private members of the base class

(1) Not accessible in the derived class

Private Inheritance

  • Public members and protected members of the base class

(1) Be private in the derived class
(2) Accessible in the derived class only

  • Private members of the base class

(1) Not accessible in the derived class

4- Virtual Functions

Virtual Functions

  • Let’s look at the example first, what will be the output?
class Person
{
  public:
    void print()
    {
      cout << "Name: " << name << endl;
    }
};
class Student: public Person
{
  public:
    void print()
    {
      cout << "Name: " << name;
      cout << ". ID: " << id << endl;
    }
};

Person *p = new Student();
p->print();   // call Person:print()?

子类和父类有同样的函数,调用子类的对象的函数,会调用子类还是父类定义的函数?

Example

virtual.cpp

#include <iostream>
#include <string>
using namespace std;

class Person
{
  public:
    string name;
    Person(string n): name(n){}
    void print()
    {
        cout << "Name: " << name << endl;
    }
};


class Student: public Person
{
  public:
    string id;
    Student(string n, string i): Person(n), id(i){}
    void print() 
    {
        cout << "Name: " << name;
        cout << ". ID: " << id << endl;
    }
};

void printObjectInfo(Person & p)
{
    p.print();
}

int main()
{
    {
        Student stu("yu", "2019");
        printObjectInfo(stu);  
    }

    {
        Person * p = new Student("xue", "2020");
        p->print(); //if print() is not a virtual function, different output
        delete p; //if its destructor is not virtual
    }
    return 0;

Name: yu
Name: xue 

调用的都是父类的函数,而这个对象是子类的对象,我们希望对于子类的对象调用子类定义的函数,结果还是调用的父类的函数

  • 在函数前加virtual就可以实现多态
#include <iostream>
#include <string>
using namespace std;

class Person
{
  public:
    string name;
    Person(string n): name(n){}
    void print()
    {
        cout << "Name: " << name << endl;
    }
};


class Student: public Person
{
  public:
    string id;
    Student(string n, string i): Person(n), id(i){}
    void print() 
    {
        cout << "Name: " << name;
        cout << ". ID: " << id << endl;
    }
};

void printObjectInfo(Person & p)
{
    p.print();
}

int main()
{
    {
        Student stu("yu", "2019");
        printObjectInfo(stu);  
    }

    {
        Person * p = new Student("xue", "2020");
        p->print(); //if print() is not a virtual function, different output
        delete p; //if its destructor is not virtual
    }


    return 0;
}
Name: yu. ID: 2019
Name: xue. ID: 2020

为什么?

Virtual Functions

  • But if we define print() function as a virtual function, the output will be different
  • Static binding: the compiler decides which function to call
  • Dynamic binding: the called function is decided at runtime
  • Keyword virtual makes the function virtual for the base and all derived classes
  • 虚函数与非虚函数的区别:绑定的区别;非虚函数是静态绑定的,虚函数是动态绑定的
  • 静态绑定:编译器在编译源代码时就决定了在这里应该执行哪个函数
  • 动态绑定:在编译时不决定应该执行哪个函数,而是在运行时根据传进来的参数来决定执行哪个函数
  • 一旦定了虚函数,对象里面第一个成员变量是一个隐含的成员变量,这个变量会指向一个虚表,这个虚表会指向对应的对象类的函数。

参考:C++虚函数表剖析

  • 纯虚类函数:没有定义,只是一个接口。这个类纯虚的类,不能创建对象
class Person2
{
  public:
    string name;
    Person2(string n): name(n){}
    virtual void print() = 0; 
};
  • If a virtual destructor is not virtual, only the destructor of the base class is executed in the follow examples
Person * p = new Student("xue", "2020");
p->print();
...
...
delete p; // if its destructor is not virtual 

析构函数一定是虚函数

5-Inheritance and Dynamic Memory Allocation

Question

  • If a base class uses dynamic memory allocation, and redefines a copy constructor and assignment operator
  • Case 1: If no dynamic memory allocation in the derived class, no special operations are needed
  • Case2: If dynamic memory is allocated in the derived class, you should redefine a copy constructor and an assignment operator

class MyMap: public MyString
{
  private:
    char * keyname;
    MyMap(const char * key, const char * value)
    {
        ...
    }
    MyMap(const MyMap & mm): MyString(mm.buf_len, mm.characters)
    {
        //allocate memory for keyname
        //and hard copy from mm to *this
    }
    MyMap & operator=(const MyMap &mm)
    {
        MyMap::operator=(mm);
        //allocate memory for keyname
        //and hard copy from mm to *this
        return *this;
    }

};

6-Examples in OpenCV

Derived cv::Mat_

  • Template matrix class derived from cv::Mat, a wrapper, more C++ style

【CPP】继承和虚函数,CPP,c++

  • Mat_ 类比Mat类更加C++化

cv::Matx

  • A template class for small matrices whose type and size are known at compilation time

【CPP】继承和虚函数,CPP,c++

  • 针对小矩阵的设计的

cv::Vec

【CPP】继承和虚函数,CPP,c++

【CPP】继承和虚函数,CPP,c++

Combined with typedef

【CPP】继承和虚函数,CPP,c++

【CPP】继承和虚函数,CPP,c++

【CPP】继承和虚函数,CPP,c++

【CPP】继承和虚函数,CPP,c++文章来源地址https://www.toymoban.com/news/detail-735240.html

到了这里,关于【CPP】继承和虚函数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • CPP语法(六)——函数模板

    模板是c++的高级特性,分为函数模板和类模板。标准模板库(STL) 模板只作用于其下方的类或函数 1.1 函数模板 函数模板定义 template 为,表示定义一个模板,尖括号表示模板参数。 模板参数主要有两种:一种是模板类型参数,另一种是模板非类型参数。 1.2 重载函数模板

    2024年04月26日
    浏览(42)
  • 【QML】QML与cpp交互(一)—— QML直接调用cpp函数

    目录 1、cpp 创建一个类 2、将类对象暴露给QML 3、QML通过对象直接调用cpp函数 类模板如下:  要求:  使用  Q_OBJECT 宏需要继承 QObject 类。Q_OBJECT能够启用信号和槽机制、使用动态属性系统。(使用 Q_OBJECT 宏的类需要通过Qt的元对象编译器(moc)进行处理。) 使用  Q_INVOKABLE 修

    2024年02月02日
    浏览(37)
  • 【C++】继承 ⑦ ( 继承中的对象模型分析 | 继承中的构造函数和析构函数 )

    下面有 3 个类 , 分别是 A 类 , B 类 , C 类 ; A 类是 基类 ; B 类 公有继承 A 类 , 并定义了新的 成员变量 y ; C 类 公有继承 B 类 , 并定义了新的 成员变量 z ; 分别定义上述 3 个类的对象 , 上述 3 个对象的内存模型如下 : A 类对象 objA 中有一个成员 int x , 在内存中只有一个 int 类型的

    2024年02月08日
    浏览(51)
  • C++委托构造函数和继承构造函数

    委托构造函数          C++11允许在一个构造函数的定义中使用另一个构造函数来简化编码工作。这被称为委托,因为构造函数暂时将创建对象的工作委托给另一个构造函数。 继承构造函数         为了进一步简化编码工作,C++11提供了一种让派生类能够继承基类构造函数的

    2024年02月13日
    浏览(41)
  • js继承的几种方式(原型链继承、构造函数继承、组合式继承、寄生组合式继承、ES6的Class类继承)

    实现原理: 子类的原型指向父类实例 。子类在自身实例上找不到属性和方法时去它父类实例(父类实例和实例的原型对象)上查找,从而实现对父类属性和方法的继承 缺点: 子类创建时不能传参(即没有实现super()的功能); 父类实例的修改会影响子类所有实例 实现原理:

    2024年02月07日
    浏览(45)
  • 4.【CPP】入门(初始化列表||explicit||static||友元||静态成员变量/函数)

    我们知道在c++11中才能在成员对象声明时初始化,像下面这样。 注意:构造函数不是初始化,而是赋初始值。那么在c++11以前该怎么初始化成员变量呢? 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次) 类中包含以下成员,必须放在初始化列表位置进行初始

    2024年01月20日
    浏览(42)
  • Python函数的重载、多态和继承

    Python重载函数是指函数可以接受不同数量或类型的参数,这样可以使得函数可以处理多种情况。函数重载是指有多个参数签名(即函数在定义时参数个数跟类型)并且有多个舍入函数体实现。也就是, 具有相同名称但实现多个不同的功能 。调用重载函数时,运行时首先评估

    2024年02月05日
    浏览(81)
  • cpp_07_类型转换构造_析构函数_深拷贝_静态成员

            基本类型之间的转换,编译器内置转换规则:int - double         类类型之间的转换,编译器不知道转换规则,需要用户提供:Cat - Dog         定义:1)单参构造                            (同于拷贝构造函数)                       2)参数类型与类类型不同

    2024年02月03日
    浏览(42)
  • 【C++】继承的基本特性(定义,赋值转换,友元,静态成员,虚拟继承,默认成员函数,作用域)

    🌏博客主页: 主页 🔖系列专栏: C++ ❤️感谢大家点赞👍收藏⭐评论✍️ 😍期待与大家一起进步! 它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。 Person是父类,也称作基类。Student是子类,也称作派生类 总结: 基类private成员

    2024年02月14日
    浏览(48)
  • <c++> 类的继承 | 基类与派生类 | 构造函数与析构函数

    🚀 个人简介:CSDN「 博客新星 」TOP 10 , C/C++ 领域新星创作者 💟 作    者: 锡兰_CC ❣️ 📝 专    栏: 从零开始的 c++ 之旅 🌈 若有帮助,还请 关注➕点赞➕收藏 ,不行的话我再努努力💪💪💪 c++ 面向对象三大特性: 封装,继承,多态 。通过本文我们将了解什么是类的

    2023年04月20日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包