专业编程基础技术教程

网站首页 > 基础教程 正文

C++中的struct完全可以被class替代,为什么不删去它呢?

ccvgpt 2024-12-02 15:44:01 基础教程 10 ℃

我有相当长的一段时间(数月)没有更新文章了。

并不是我放弃了写技术文章,而是因为这段时间,我把精力主要放在了图像智能算法的学习上了。去年12月时,我对图像智能算法还懵懵懂懂,做着 Linux 嵌入式应用程序开发,现在我已经正式入职到算法公司了,收入翻了一番,哈哈,不过累了好多。废话就到这里,我的转行辛酸史,以后再详谈。

C++中的struct完全可以被class替代,为什么不删去它呢?

坦诚的说,就编程语言而言,因为一直在做 Linux 嵌入式程序开发的缘故,我对C语言更加了解一点,读者应该能够发现,我之前的大部分文章都是关于C语言的。不过现在做算法,C++更加适合。C++和C语言虽然很像,但是在细节上还是有所区别的。今天阅读前辈同事的代码时,注意到了 struct 关键字,这个关键字在C++中做了不少扩展。本文将尝试做下总结。

C语言与C++中的struct

struct关键字是C语言中非常重要的关键字,在实际的C语言程序开发中,struct 不仅可以用于封装各种复杂的数据结构,还能够实现一些开发技巧——比如辅助数组赋值、模拟类等等,这些我之前的文章都讨论过。C++不仅保留了C语言中 struct 的功能,还做了不少扩展,具体的可以通过下面这个表说明:

请看下面这段C++代码示例,我们首先使用 struct 定义了 S1,接着又定义了 S2,S2 继承了 S1,因此我们可以在 test2 中使用 S1 中定义的成员 a、b。同时也可以看出,C++中的 struct 还可以定义成员函数,包括构造函数和析构函数。

#include <iostream>

using namespace std;

struct S1 {
    int    a;
    int    b;

    S1() {
        a = 1;
        b = 2;
    }

    void print_mem() {
        cout << "a = "<< a << ", b = "<<b <<endl;
    }
};

struct S2: S1 {
    int        c;
    ~S2() {
        cout << "S2 exit, c = " << c << endl;
        cout << "a = "<< a << ", b = "<<b <<endl;
    }
};

int main()
{
    S1 test1;
    test1.print_mem();

    S2 test2;
    test2.a = 3;
    test2.b = 4;
    test2.c = 5;

    return 0;
}

编译并执行上述C++代码,不出意外地得到如下输出:

$ g++ t1.cpp 
$ ./a.out 
a = 1, b = 2
S2 exit, c = 5
a = 3, b = 4

C++ 中的 struct 和 class 关键字

从上面的例子不难看出,C++中的 struct 除了像C语言那样可以定义数据结构外,还可以像 class 关键字那样定义成员函数。不过,二者是有区别的。

成员的默认访问控制属性

首先,struct 默认的访问控制属性是 public,而 class 默认的访问控制属性是 private,这一点可以通过下面这段C++代码示例看出:

struct A {
    int a;
};
class B {
    int b;
};

A ta;
ta.a = 1; // 没有问题

B tb;
tb.b = 2; // 编译报错

继承的默认访问控制属性

类似的,在继承的过程中,struct 和 class 关键字的默认访问控制属性也是有所区别的:struct 默认 public,class 默认 private,例如下面这段C++ 代码:

struct A {
    int a;
};
struct B: A {
    int b;
};

B tb;
tb.a = 1; // 正常

这是没有问题的,对象 tb 可以访问由 A 继承而来的成员 a。但是如果将 B 的 struct 改为 class,也即:

struct A {
    int a;
};
class B: A {
    int b;
};

B tb;
tb.a = 1; // 编译报错

此时编译就会报错,提示“‘int A::a’ is inaccessible”,因为 class 的默认继承属性为 private。现在我们将 A 的 struct 修改为 class,B 的 class 再改回 struct,会发现,对象 tb 依然能够正常访问成员 a:

class A {
public:
    int a;
};
struct B: A {
    int b;
};

B tb;
tb.a = 1; // 正常

应注意,这里的讨论重点是继承的默认访问控制属性,因此我们将 A 中的 a 定义为 public 的。

可以看出,当 class 和 struct 混合使用时,默认的访问控制属性由子类决定,而不是由基类决定。不过,依赖默认属性不是特别清晰的写法,在实际的C++程序开发中,更推荐的做法是指明继承的方式:

class B: private A {
    ...
};
class B: public A {
    ...
};

定义模板

相较于C语言,C++还能够定义模板函数,请看下面这段代码示例:

template<typename T>                                                                                             
void fun(T num) {
     cout << "num = " << num << endl;
} 
fun(1); // num = 1
fun(1.01); // num = 1.01

在一些开源工程中,我还发现过有使用 class 定义模板函数的,也即使用class替换typename关键字:

template<class T>                                                                                             
void fun(T num) {
     cout << "num = " << num << endl;
} 

这种定义方式和上面使用typename的定义方式完全相同,但是 struct 就不能用于定义模板函数,如果读者尝试了,应该会得到编译报错的结果。

小结

本文先是讨论了 struct 关键字在C语言和C++中的不同,不难发现,C++对 struct 关键字是做了不少扩充的,这些扩充让 struct 看起来更像是 class 关键字。事实上,我认为就单纯C++来说,class 关键字是完全可以取代 struct 的,C++ 仍然保留着 struct 关键字,其中一个重要原因就是兼容C语言。既然保留了 struct 关键字,总不能让它完全等价于 class,因此二者在一些细节上有区别,这些轻微的区别往往能够针对不同的需求提供不同的方便:struct 更适合封装数据结构,class 则更适合封装对象。

Tags:

最近发表
标签列表