标签 c++ 下的文章

使用形式:

  • using指令(using directive)的使用形式为using namespace std
  • using声明(using declaration)的使用形式为using std::cout

作用差别:

  • using指令的作用是让std内的所有声明在当前文件作用域内都可用,我们可以使用域作用符::直接访问std命名空间内的所有定义。
  • 而using声明只是在当前作用域内声明std命名空间内的一个函数,只有被声明的函数才能在当前作用域内使用。

使用建议:using声明的作用域更小,可以更有效地缩小使用作用域,避免函数冲突问题,更推荐使用。

一、友元

友元可以允许其他类或者函数访问自己的非共有成员,如果类想把它的函数作为友元,只需要增加一条以friend开头的函数声明即可。

1.1 添加外部函数作为友元

以下一个学生类,类中保存了学生的年龄、名字以及性别信息:

class stu_st {
private:
    int age;
    string name;
    char sex;
};

现在希望在类外面以函数的形式来计算两个学生的年龄之和,因为age成员是私有的,所以目前类外部的函数是无法获取到学生年龄,这个想法无法完成。但是有了友元之后,这个想法就能实现了。只要在类中添加友元定义,外部再实现函数就可以了:

class stu_st {
    friend int figure_age(const stu_st &a, const stu_st &b);
    // ...
};

// 实现计算年龄函数
int figure_age(const stu_st &a, const stu_st &b) {
    return a.age + b.age;
}
友元是不区分共有和私有的,以友元修饰的函数即使声明在private域,外部也是能访问的。

1.2 以外部类作为友元

新增一个老师类,老师能获取学生的年龄:

class teacher_st;
class stu_st {
    friend class teacher_st;
    // ...
};

class teacher_st {
public:
    unsigned int get_stu_age(const stu_st &stu) {
        return stu.age;
    }
};

1.3 静态成员变量

当类中存在静态变量时,友元类和函数也是能直接访问这个变量的。

以下代码声明了一个teacher_st作为老师类,声明了一个stu_st作为学生类,学生类中有一个静态变量total_count表示学生的总数,老师作为友元类来获取这个数量:

#include <iostream>

using namespace std;

class teacher_st;
class stu_st {
    friend class teacher_st;
private:
    static unsigned int total_count;
};

class teacher_st {
public:
    unsigned int get_stu_count() {
        return stu_st::total_count;
    }
};

unsigned int stu_st::total_count = 10;

int main() {
    teacher_st t;
    cout << t.get_stu_count() << endl;
    return 0;
}

运行结果:

二、运算符重载

2.1 运算符重载语法

运算符重载给类提供了大大的便利性,使得自定义类型也能和内置类型一样使用系统操作符。

运算符重载的语法:

void operator+(const stu_st &s);

各元素说明:

  • void:返回值类型
  • operator+:表示重载运算符+
  • s:运算符的参数
运算符重载有几种不同的写法,可以写在类中,也可以写在类外面。

在类中声明

以学生类为例,重载小于符号<使得类可以直接通过年龄大小作为对比:

class stu_st {
private:
    unsigned int age;
    string name;
public:
    stu_st(int age, string name) : age(age), name(name) {
    }
    // 重载小于符号
    bool operator<(const stu_st &x) const {
        return this->age < x.age;
    }
};

在类外面声明

因为类外面的函数无法直接访问类内部数据,因此,类外面的函数需要被声明为类的友元函数。

class stu_st {
private:
    unsigned int age;
    string name;
public:
    // 声明重载操作符>
    friend bool operator>(const stu_st &, const stu_st &);
};

bool operator>(const stu_st &a, const stu_st &b) {
    return a.age > b.age;
}

注意

在类内部重载操作符,编译器默认会把this作为第一个参数传入,因此,重载时无需再传入当前类对象本身。例如:

bool operator<(const stu_st &x) const

这就表示用当前对象和x对象作对比。而外部声明的函数,因为没有封装在类中,不能传入this指针,因此声明时需要传入对象本身。即:

friend bool operator>(const stu_st &, const stu_st &);

2.3 重载输入输出运算符

重载输入和输出运算符需要注意的一个问题是:与iostream标准库相关的运算符重载,必须是非成员函数。

#include <iostream>
#include <ostream>
#include <string>

using namespace std;

class stu_st {
private:
    unsigned int age;
    string name;
public:
    stu_st() {};

    friend istream &operator>>(istream &, stu_st &);
    friend ostream &operator<<(ostream &os, const stu_st &stu);
};

// 重载输出运算符
ostream &operator<<(ostream &os, const stu_st &stu) {
    os << "Name: " << stu.name << "\tAge: " << stu.age;
    return os;
}

// 重载输入运算符
istream &operator>>(istream &is, stu_st &stu) {
    is >> stu.name >> stu.age;
    return is;
}

int main() {
    stu_st stu;
    cin >> stu;
    cout << stu;
}

测试效果:

一、class和struct的区别

C++中class和struct的区别:

  1. 继承权限,struct的默认继承权限为public,class的默认继承权限为private。
  2. 访问权限,struct的默认访问权限为public,class的默认访问权限为private。

网上还流传着其他一些的区别,但总体来说最大的区别就是这两点,其他的区别或许并不常用到。

二、C和C++中struct的区别

第一、C++中的struct可以定义成员函数,但是C语言不行,C语言中的结构体可以定义函数指针。

例如以下代码:

struct stu_st {
    void print();
};

int main() {
    return 0;
}

使用GCC编译会报错:

第二、C语言声明结构体必须要加struct,C++不用。

C语言中如果不加struct声明变量,编译器会报错:

如若不想加struct修饰,则需要使用typedef来重新定义类型。

第三、C语言中空结构体大小为0,C++中结构体大小为1。

相同的代码:

#include "stdio.h"

struct stu_st {
};

int main() {
    printf("%u\n", (unsigned int)sizeof(struct stu_st));
    return 0;
}

使用gccg++编译结果也不一样:

区别:

  1. 指针是一个变量类型,引用只是一个变量别名。
  2. 指针可以不用初始化,引用必须初始化。
  3. 指针可以指向空地址,引用不能指向空。
  4. 指针初始化后可以修改,引用不能修改。

其他:

  • 引用本质上也是一个指针,内部实现是一个常量指针。
  • C++中一般建议使用引用,不要使用指针。函数传值建议使用const引用。

一、几者的区别

  1. malloc/free是c语言中分配内存空间的函数,malloc创建空间,free释放空间。
  2. new/delete是c++中分配内存的操作符,new创建空间,delete删除空间。
  3. new[]/delete[]也是C++中的操作符,用来给数组分配和释放空间。
  4. malloc只是简单的分配内存空间,而new分配空间后会自动调用对象的析构函数。相对应的,free也只是简单的删除内存空间,delete则会调用对应析构函数。

二、案例

定义一个简单的类:

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

使用malloc/freenew/delete分别创建和释放对象:

#include<iostream>
#include<stdlib.h>
using namespace std;
 
int main{
    cout << "---malloc/free---" << endl;
    A *a1 = (A*)malloc(sizeof(A)); 
    free(a1);
    cout << "---new/delete---" << endl;
    A *a2 = new A;
    delete a2;
    return 0;
}

运行:

---malloc/free---
---new/delete---
A()
~A()

可见,malloc确实没有调用构造函数,free也没有调用析构函数。

三、delete和delete[]

deletenew对应,delete[]new[]对应。delete用来删除单个对象,delete[]删除对象数组。

deletedelete[]的区别在于后者会调用数组内每一个元素的析构函数,而delete只会调用一个。两者在对于内置元素类型时功能一致,对于复杂类型delete可能会报错。

int main(){
    cout << "------" << endl;
    int *p1 = new int[10];
    delete p1;

    cout << "---delete[]---" << endl;
    A *a2 = new A[1];
    delete []a2;

    cout << "---delete---" << endl;
    A *a1 = new A[1];
    delete a1;
    return 0;
}

执行会报错:

可见,对内置类型而言,互相使用并没有问题。但是对自定义类型而言,delete和delete[]并不能乱用。