C++

重学C++系列(七)面向对象

Posted by YaPi on January 23, 2022

函数

内联函数

如果一个函数事内联得,那么在编译时,编译器会把函数的代码副本放置在每个调用该函数的地方。

引入内联函数的目的事为了解决程序中函数调用效率的问题。内联函数内部不能有太复杂的逻辑,编译 器有时会有自己的优化策略,所以内联不一定起作用。 使用inline关键字创建

#include <iostream>


inline int MaxValue(int a, int b){
    return a +b;
}

int main() {
    int a=2,b=3;
    int c = MaxValue(a,b);
    std::cout<< c << std::endl;
    return 0;
}

内联函数其实就是用空间换时间,函数调用对应很多操作,直接将被调用函数的内部逻辑拷贝到调用的地方。 所以逻辑不能太复杂,不然还是会失效。

c++ 使用struct,class来定义一个类 struct的默认成员权限事public,class的默认成员权限事private,除此之外,二者无差别

struct A {
    string a;
    string b;
    union {
        char aa;
        int bb;
    };
};

使用union来表示 aa 或 bb 只能有一个有值

class complex {
public:
    complex(double r, double i);
    virtual ~complex();
    // 可以写在cpp文件内,但是简单的函数一般直接写这儿
    // 编译器可能会做优化,优化成一个inline函数
    double setReal(double d){
        _real = d;
    }
    double getReal()const{
        return _real;
    }
    double setImage(double i){
        _image = i;
    }
    double getImage()const{
        return _image;
    }


private:
    double _real;
    double _image;
};

基础构造

class Complex {
private:
    int _a;
    int _b;
protected:
    // 输出重载 const关键修饰 不允许改变
    friend std::ostream& operator<<(std::ostream& os, const Complex &x);
    // 输入重载
    friend std::istream& operator>>(std::istream& is,Complex &x);
public:
    void setA(const int a){_a = a;}
    int getA(){return _a;}
    void setB(const int b){_b = b;}
    int getB(){return _b;}
    // 默认构造函数
    Complex();
    // 构造函数
    Complex(int a,int b);
    // 拷贝构造
    Complex(const Complex& x);
    // 析构函数
    virtual ~Complex();
    // + 操作符重载
    Complex operator+(const Complex& x);
    // = 操作符重载
    Complex operator=(const Complex& x);
    // 前置 ++ 操作符
    Complex& operator++();
    // 后置 ++ 操作符
    Complex operator++(int);
};


Complex::Complex() {
    _a = 0;
    _b = 0;
}
Complex::Complex(int a, int b) {
    _a = a;
    _b = b;
}

Complex::~Complex() {
    cout << "~Complex" << endl;
}
Complex Complex::operator+(const Complex & x) {
    // 会产生临时对象
//    Complex tmp;
//    tmp._a = x._a + _a;
//    tmp._b = x._b + _b;
    return Complex(_a + x._a,_b+x._b);
}
// 复制
Complex Complex::operator=(const Complex & x) {
    if (this != &x){
        _a = x._a;
        _b = x._b;
    }
    return *this;
}
// 拷贝构造函数 防止产生副本
Complex::Complex(const Complex& x) {
    _a = x._a;
    _b = x._b;
}

// 前置 ++
Complex& Complex::operator++() {
    _a++;
    _b++;
    return *this;
}

// 后置++
Complex Complex::operator++(int) {
    Complex tmp(*this);
    _a++;
    _b++;
    return tmp;
}
// 输出重载
std::ostream& operator<<(std::ostream& os, const Complex &x){
    os << "a value is " << x._a << "b value is "<< x._b <<endl;
    return os;
}

// 输入重载
std::istream& operator>>(std::istream& is,Complex &x){
    // 使用空格或换行来赋值多个
    is >> x._a >> x._b;
    return is;
}

具体调用

int main() {
    Complex a(1,2);
    std::cout<< a.getA() << std::endl; // 1
    std::cout<< a.getB() << std::endl; // 2
    a.setA(2);
    a.setB(1);
    std::cout<< a.getA() << std::endl; // 2
    std::cout<< a.getB() << std::endl; // 1
    Complex b(2,3);
    Complex c ;
    c = a + b; // 若操作符 + 重载函数中使用了临时对象,就会有拷贝的过程
    // Complex c = a + b; // 直接创建对象会少一个拷贝的步骤
    // Complex d(c);// 使用存在对象创建一个新对象也会调用拷贝构造方法
    // 输出重载
    std::cout<< a << std::endl;
    // 接受输入的值 并赋值
//    int cc;
//    std::cin >> cc;
//    std::cout << cc <<std::endl;
    // 输入重载
    Complex e;
    std::cin >> e;
    std::cout << e << std::endl;
    return 0; // text 代码区
}
头文件的重复包含问题

为了避免同一个文件被include多次,有两种方式

  1. 使用宏
#ifndef \__SOMEFILE_H\__
#define \__SOMEFILE_H\__
...
#endif

使用宏来防止同一个文件被多次包含,可移植性好,但是无法防止宏名重复,难以排错。

  1. #pragma once 使用编译器来防止同一个文件被多次包含;可防止宏名重复,易排错,但是可移植性不好
深拷贝/浅拷贝,写时复制

浅拷贝:只拷贝指针地址,c++默认拷贝构造函数于赋值运算符重载都是浅拷贝;节省空间,但 容易引发多次释放;

深拷贝:重新分配堆内存,拷贝指针指向内容。浪费空间,但不是导致多次释放。