【个人笔记】SUSTech于老师C/C++课程(chap.11-chap.15)

 本博客仅用来记录自己学习本课程的笔记。

课程视频: 快速学习C和C++,基础语法和优化策略,学了不再怕指针(南科大计算机系原版)_哔哩哔哩_bilibili

课件与代码:GitHub - ShiqiYu/CPP: Lecture notes, projects and other materials for Course 'CS205 C/C++ Program Design' at Southern University of Science and Technology.

1、parameter表示形参,argument表示实参

2、C++中class,如果不进行编写,默认的函数

1)默认构造函数,函数内没有任何内容

2)默认析构函数,函数没有任何内容

3)默认拷贝构造函数,函数会将非静态值复制给目标(注意与4进行区分)

4)默认拷贝赋值运算符,函数会将非静态值复制给目标(注意与3进行区分)

3、默认函数在使用时会出现的问题:

#pragma once

#include <iostream>
#include <cstring>

class MyString
{
  private:
    int buf_len;
    char * characters;
  public:
    MyString(int buf_len = 64, const char * data = NULL)
    {
        std::cout << "Constructor(int, char*)" << std::endl;
        this->buf_len = 0;
        this->characters = NULL;
        create(buf_len, data);
    }
    ~MyString()
    {
        delete []this->characters;
    }
    bool create(int buf_len,  const char * data)
    {
        this->buf_len = buf_len;

        if( this->buf_len != 0)
        {
            this->characters = new char[this->buf_len]{};
            if(data)
                strncpy(this->characters, data, this->buf_len);
        }
    
        return true;
    }
    friend std::ostream & operator<<(std::ostream & os, const MyString & ms)
    {
        os << "buf_len = " << ms.buf_len;
        os << ", characters = " << static_cast<void*>(ms.characters);
        os << " [" << ms.characters << "]";
        return os;
    }
};
#include <iostream>
#include "mystring.hpp"

using namespace std;

// Why memory leak and memory double free?
int main()
{
    {
        MyString str1(10, "Shenzhen");
        cout << "str1: " << str1 << endl;

        MyString str2 = str1; 
        cout << "str2: " << str2 << endl;

        MyString str3;
        cout << "str3: " << str3 << endl;
        str3 = str1;
        cout << "str3: " << str3 << endl;
    }
    cout << "end of main()" << endl; // it will not be printed out
    return 0;
}

如上图所示,三个MyString会调用三次构造函数,但是character同时指向一个地址,在最后调用析构函数时会调用三次删除character的内存,即重复删除内存。

解决办法:1)、hard copy,在构造函数和拷贝构造函数中进行重新申请一块内存

2)、soft copy,使用refcount(reference count)

4、smart pointers(原理就是一种模板类)

1)shared_ptr不同类的对象指向的同一地址,最后可以自动调用析构函数

2)unique_str一个地址只能由一个指针指向,最后可以自动调用析构函数,在转移对象时使用move函数

5、访问控制

关于友元类见http://t.csdnimg.cn/PSwjK

6、Derived class继承类

#include<iostream>

using namespace std;

class Student {
protected:
	const char* name;
	int num;

public:
	Student(const char* name, int num) :name(name), num(num) {};
	void display(void);
};

void Student::display(void) {
	cout << "name:" << name << "num:" << num << endl;
}

class Pri_Student:public Student {
private:
	int height;
	int weight;
public:
	Pri_Student(const char* name, int num, int h, int w) :Student(name, num) { height = h; weight = w; };
	//不仅需要对派生类增加的数据成员的初始化,也要考虑基类的数据成员的初始化(直接调用基类的初始化函数)
	//格式:派生类的构造函数(全部成员参数):基类的构造函数(基类的成员参数){派生类参数的初始化}
	//实现形式非常类似与参数初始化列表

	//也可以用参数初始化列表一并进行参数初始化
	//Pri_Student(char name[], int num, int h, int w) :Student(name, num) ,height(h),weight(w){};
	void display1(void);
	void display(void); //在子类中也可以定义与基类相同名字的函数,其定义会覆盖基类的函数定义
};

void Pri_Student::display(void) {
	cout << "display" << endl;
}

void Pri_Student::display1(void) {
	cout << "name: " << name << "num: " << num << "height: " << height << "weight: " << weight <<  endl;
}

int main(void) {
	Pri_Student S1("Sam", 1006, 183, 72);
	S1.display();
	S1.display1();
	return 0;
}

1)如果在派生类中出现内存的申请,应该重新编写a copy constructor 和 an assignment operator.

2)对于不同继承方式:

1)使用public,则父类的public与protected依旧是public与protected,private不能继承;

2)使用protected,则父类的public与protected都为protected访问控制,private不能继承;

3)使用private,则父类的public与protected都为private访问控制,private不能继承;

3)* 友元函数与派生类的区分: # 友元函数需要在基类中声明,可以直接访问基类的成员数据(私有成员也可以直接访问) # 派生类只能访问基类中的公用变量以及保护变量,不可以直接访问基类中的私有变量

7、虚函数,用来

  1. 继承和扩展:派生类可以继承基类的虚函数,并提供一个新的实现(重写)。这样可以保持接口的一致性,同时允许每个派生类根据自己的需要定制行为。

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

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

class Person2
{
  public:
    string name;
    Person2(string n): name(n){}
    virtual void print() = 0; // = 0表示纯虚函数,表示改类只能进行继承,不能进行声明
};

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
    }

    { //if you want to call a function in the base class
        Student stu("li", "2021");
        stu.Person::print();

        Person * p = new Student("xue", "2020");
        p->Person::print(); 
        delete p; 
    }

    return 0;
}

使用virtual function时输出结果为

Name: yu. ID: 2019
Name: xue. ID: 2020
Name: li
Name: xue

不使用virtual function时输出结果为

Name: yu
Name: xue
Name: li
Name: xue

8、类模板(同函数模板)

#include <iostream>
using namespace std;

// Class Template
template<typename T>
class Mat
{
    size_t rows;
    size_t cols;
    T * data;
  public:
    Mat(size_t rows, size_t cols): rows(rows), cols(cols)
    {
        data = new T[rows * cols]{};
    }
    ~Mat()
    {
        delete [] data;
    }
    Mat(const Mat&) = delete; //删除拷贝函数
    Mat& operator=(const Mat&) = delete; //删除赋值拷贝
    T getElement(size_t r, size_t c);
    bool setElement(size_t r, size_t c, T value);
};
template <typename T>
T Mat<T>::getElement(size_t r, size_t c)
{
    if ( r >= this->rows || c >= this->cols)
    {
        cerr << "getElement(): Indices are out of range" << endl;
        return 0;
    }
    return data[ this->cols * r + c];
}
template <typename T>
bool Mat<T>::setElement(size_t r, size_t c, T value)
{
    if ( r >= this->rows || c >= this->cols)
    {
        cerr << "setElement(): Indices are out of range" << endl;
        return false;
    }

    data[ this->cols * r + c] = value;
    return true;
}

template class Mat<int>; // Explicitly instantiate template Mat<int>
//template Mat<float> and Mat<double> will be instantiate implicitly
int main()
{
    Mat<int> imat(3,4);
    imat.setElement(1, 2, 256);
    Mat<float> fmat(2,3);
    fmat.setElement(1, 2, 3.14159f);
    Mat<double> dmat(2,3);
    dmat.setElement(1, 2, 2.718281828);

    // Mat<float> fmat2(fmat); //error

    // Mat<float> fmat3(2,3);
    // fmat3 = fmat; //error

    cout << imat.getElement(1,2) << endl;
    cout << fmat.getElement(1,2) << endl;
    cout << dmat.getElement(1,2) << endl;
    
    return 0;
}

9、模板非类型参数

#include <iostream>
using namespace std;

// Class Template
template<typename T, size_t rows, size_t cols>
class Mat
{
    T data[rows][cols];
  public:
    Mat(){}
    // // the default copy constructor will copy each element of a static array member
    // // so we do not 'delete' the copy constructor
    // // the same with the assignment operator
    // Mat(const Mat&) = delete;
    // Mat& operator=(const Mat&) = delete;
    T getElement(size_t r, size_t c);
    bool setElement(size_t r, size_t c, T value);
};
template<typename T, size_t rows, size_t cols>
T Mat<T, rows, cols>::getElement(size_t r, size_t c)
{
    if ( r >= rows || c >= cols)
    {
        cerr << "getElement(): indices are out of range" << endl;
        return 0;
    }
    return data[r][c];
}
template<typename T, size_t rows, size_t cols>
bool Mat<T, rows, cols>::setElement(size_t r, size_t c, T value)
{
    if ( r >= rows || c >= cols)
    {
        cerr << "setElement(): Indices are out of range" << endl;
        return false;
    }

    data[r][c] = value;
    return true;
}

template class Mat<int, 2, 2>; // Explicitly instantiate template Mat<int, 2, 2>
typedef Mat<int, 2, 2> Mat22i;

//template Mat<float, 3, 1> will be instantiate implicitly

int main()
{
    Mat22i mat;

    mat.setElement(2, 3, 256);
    cout << mat.getElement(2, 3) << endl;

    mat.setElement(1, 1, 256);
    cout << mat.getElement(1, 1) << endl;

    Mat<float, 3, 1> vec;
    vec.setElement(2, 0, 3.14159f);
    cout << vec.getElement(2, 0) << endl;

    Mat<float, 3, 1> vec2(vec); //使用了拷贝构造函数,静态数组能够全部拷贝
    cout << vec2.getElement(2, 0) << endl;

    // vec2 = mat; //error

    return 0;
}

10、类模板的特例化(类似于函数模板的特例化)

11、标准类:string、array、stack、vector、list、map、set......

12、输入输出流,用来编写日志将输出和error分开进行输出

13、assert

assert 是一个宏,用于在运行时(当程序正在执行时)检查特定条件,在调试程序时非常有用。要使用它,你需要在程序中包含头文件“assert.h”。
实例:

没有定义NDEBUG宏时,

#include <iostream>
#include <cassert>

int main(int argc, char ** argv)
{
    assert( argc == 2);
    std::cout << "This is an assert example." << std::endl;
    return 0;
}

输出:

$ ./a.out 
a.out: assert.cpp:6: int main(int, char**): Assertion `argc == 2' failed.
Aborted (core dumped)

定义了NDEBUG宏时,(注意要在cassert前进行定义)

#include <iostream>
#define NDEBUG
#include <cassert>

int main(int argc, char ** argv)
{
    assert( argc == 2);
    std::cout << "This is an assert example." << std::endl;
    return 0;
}

输出:

$ ./a.out 
This is an assert example.
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值