struct和class区别、三种继承及虚继承、友元类

2024-03-04 07:20

本文主要是介绍struct和class区别、三种继承及虚继承、友元类,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

之前只知道在C++中类和结构体的区别只有默认的防控属性(访问控制)不同,struct是public的,而class是private的。但经过上网查资料才发现,除了这个不同之外,还有很多的知识点需要掌握。下面就听我一一道来~

1、首先比较一下C中的结构体和C++中的结构体区别

C++中的struct是对C中的struct进行了扩充,所以增加了很多功能,主要的区别如下图所示:

在这里插入图片描述
上面罗列了在声明时的区别,在使用的过程中也有区别:

在C中使用结构体时需要加上struct,或者对结构体使用typedef取别名,而C++可直接使用,例如:

结构体声明,C和C++使用同一个
struct Student
{
    int  iAgeNum;
    string strName;
}
typedef struct Student Student2;//C中取别名

struct  Student  stu1;    //C中正常使用
Student2   stu2;        //C中通过取别名的使用
Student    stu3;        //C++使用
 

与C++实际上编程思想的区别,C是面向过程,C++面向对象
所以在C中结构体就是不同类型数据的集合,并不涉及算法和操作。
而C++是把数据变量及对这些数据变量的相关算法和操作给封装起来。

2、C++中Struct与Class的区别

在C++中引入struct是为了保持对C程序的兼容,在引入之后C++对其进行了扩充,现在struct可以拥有静态成员、成员数据可进行初始化、拥有函数、也可以继承、甚至多态也支持。从表面看起来两者之间像是没有区别,有时你把程序中的所有class改为struct,程序也照常运行。之所以说是看起来呢,两者之间肯定还是有差别的啦。

2.1、内部成员变量及成员函数的默认防控属性

struct默认防控属性是public的,而class默认的防控属性是private的,例如:

struct A
{
    int iNum;
}
class B
{
    int iNum;
}

A a;
a.iNum = 2;        //没有问题,默认防控属性为public
B b;
b.iNum = 2;        //编译出错,默认防控属性为private
 

在继承关系,struct默认是public的,而class是private,例如:

struct A
{
    int   iAnum;
}
struct B : A
{
    int   iBnum;
}

A a;
a.iAnum = 1;    //在struct情况下是正确的,在class情况下是错误的
 

在是struct的情况下B是默认public继承A的。如果将上面的struct改成class,那么B是private继承A的。

上面的列子都是struct继承struct,class继承class,那么class与struct继承会怎样呢?
结论是:默认的防控属性取决于子类而不是基类,例如:

struct A{};
class B : A {};    //默认为private继承
struct C : B{};    //默认为public继承
 

所以我们在写代码的时候,为了不引起歧义,最好指明继承的方式,而不要用默认的继承,例如:

class B : public A{};
struct B : public A{};
 

2.3、模板中的使用

class这个关键字还可用于定义模板参数,就像typename。但是strcut不用与定义模板参数,例如:

template< typename T, typename Y >    //可以把typename 换成 class
int  Func( const T& t, const Y& y )
{
    //TODO
}

2.4、{}赋初值的讨论

因为C++是对C的扩充,那么它就兼容过去C中struct的特性,例如:

当然这里在class时,默认的防控属性为private,所以出错正常,但这是它们之间的一个区别吗?不是的。
在struct中加入一个构造函数(或虚函数),你会发现struct也不能用{}赋值了。嗯?头顶上有个大大的问号。

原因是以{}的方式来赋初值,只是用一个初始化列表来对数据进行按顺序的初始化,如果上面写成A a = {‘p’,7};则c1,i2被初始化,而db3没有。这样简单的copy操作,只能发生在简单的数据结构上,而不应该放在对象上。加入一个构造函数或是一个虚函数会使strcut更体现出一种对象的特性,而是{}操作不在有效

因为加入这样的函数(构造和虚函数),使得类的内部结构发生了变化。而加入一个普通的成员函数呢?你会发现{}依旧可用。其实你可以将普通的函数理解成对数据结构的一种算法,这并不打破它数据结构的特性。

2.5总结

通过上面的总结,你会发现两者的差别确实没有很大。尤其是在我们书写程序的过程中显示指明防控属性时,那我们什么时候用class,什么时候用struct呢?

个人建议:当你觉得你要做的更像是一种数据结构集合的话,那么用struct。如果你要做的更像是一种对象的话,那么用class

https://blog.csdn.net/weixin_39640298/article/details/84349171

参考资料:
https://www.cnblogs.com/starfire86/p/5367740.html
https://www.cnblogs.com/Carrie-0173/p/6357715.html
https://blog.csdn.net/lailaiquququ11/article/details/82904406

下表汇总了不同继承方式对不同属性的成员的影响结果
继承方式/基类成员public成员protected成员private成员
public继承publicprotected不可见
protected继承protectedprotected不可见
private继承privateprivate不可见

虚继承


//间接基类A
class A{
protected:int m_a;
public:int m_ab;int m_ac;int m_abc;
};//直接基类B
class B: virtual public A{  //虚继承
protected:int m_b;
public:int m_bc;int m_ab;int m_abc;
};//直接基类C
class C: virtual public A{  //虚继承
protected:int m_c;
public:int m_bc;int m_ac;int m_abc;
};//派生类D
class D: public B, public C{
public:void seta(int a){ m_a = a; }  //正确void setb(int b){ m_b = b; }  //正确void setc(int c){ m_c = c; }  //正确void setd(int d){ m_d = d; }  //正确
private:int m_d;
};int main(){D d;//d.m_bc = 1; // compile error// Member 'm_bc' found in multiple base classes of different typesd.B::m_bc = 1; d.C::m_bc = 2;cout<<d.B::m_bc << " " << d.C::m_bc <<endl; // 1 2d.m_ab = 3;cout<<d.m_ab << " " << d.B::m_ab << " " << d.C::m_ab <<endl; // 3 3 -858993460d.B::m_ab = 4;cout<<d.m_ab << " " << d.B::m_ab << " " << d.C::m_ab <<endl; // 4 4 -858993460d.C::m_ab = 5;cout<<d.m_ab << " " << d.B::m_ab << " " << d.C::m_ab <<endl; // 4 4 5//d.m_abc = 3; // compile error// Member 'm_abc' found in multiple base classes of different typesd.B::m_abc = 3; d.C::m_abc = 4;cout<<d.B::m_abc << " " << d.C::m_abc <<endl; // 3 3return 0;
}

http://c.biancheng.net/view/2280.html

友元

15、 判断:子类可以访问父类的保护成员,子类的友元类也可以访问父类的保护成员。(对)
考察继承与访问级别的基本概念。让子类的友员通过子类对象去访问父类保护成员,保证题目更加严谨。
16、 下面对继承的描述正确的是:
A.父类的友元类可以访问子类保护成员
B.子类的友元类可以访问父类的私有成员
C.子类可以访问父类的保护成员
D.父类可以访问子类的保护成员

参考资料

http://c.biancheng.net/view/2269.html

虚继承

https://blog.csdn.net/aixiaodeshushu/article/details/99759177

https://www.cnblogs.com/heyonggang/p/3255155.html

这篇关于struct和class区别、三种继承及虚继承、友元类的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/772403

相关文章

native和static native区别

本文基于Hello JNI  如有疑惑,请看之前几篇文章。 native 与 static native java中 public native String helloJni();public native static String helloJniStatic();1212 JNI中 JNIEXPORT jstring JNICALL Java_com_test_g

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使

Collection List Set Map的区别和联系

Collection List Set Map的区别和联系 这些都代表了Java中的集合,这里主要从其元素是否有序,是否可重复来进行区别记忆,以便恰当地使用,当然还存在同步方面的差异,见上一篇相关文章。 有序否 允许元素重复否 Collection 否 是 List 是 是 Set AbstractSet 否

JavaSE——封装、继承和多态

1. 封装 1.1 概念      面向对象程序三大特性:封装、继承、多态 。而类和对象阶段,主要研究的就是封装特性。何为封装呢?简单来说就是套壳屏蔽细节 。     比如:对于电脑这样一个复杂的设备,提供给用户的就只是:开关机、通过键盘输入,显示器, USB 插孔等,让用户来和计算机进行交互,完成日常事务。但实际上:电脑真正工作的却是CPU 、显卡、内存等一些硬件元件。

javascript中break与continue的区别

在javascript中,break是结束整个循环,break下面的语句不再执行了 for(let i=1;i<=5;i++){if(i===3){break}document.write(i) } 上面的代码中,当i=1时,执行打印输出语句,当i=2时,执行打印输出语句,当i=3时,遇到break了,整个循环就结束了。 执行结果是12 continue语句是停止当前循环,返回从头开始。

maven发布项目到私服-snapshot快照库和release发布库的区别和作用及maven常用命令

maven发布项目到私服-snapshot快照库和release发布库的区别和作用及maven常用命令 在日常的工作中由于各种原因,会出现这样一种情况,某些项目并没有打包至mvnrepository。如果采用原始直接打包放到lib目录的方式进行处理,便对项目的管理带来一些不必要的麻烦。例如版本升级后需要重新打包并,替换原有jar包等等一些额外的工作量和麻烦。为了避免这些不必要的麻烦,通常我们

ActiveMQ—Queue与Topic区别

Queue与Topic区别 转自:http://blog.csdn.net/qq_21033663/article/details/52458305 队列(Queue)和主题(Topic)是JMS支持的两种消息传递模型:         1、点对点(point-to-point,简称PTP)Queue消息传递模型:         通过该消息传递模型,一个应用程序(即消息生产者)可以

深入探讨:ECMAScript与JavaScript的区别

在前端开发的世界中,JavaScript无疑是最受欢迎的编程语言之一。然而,很多开发者在使用JavaScript时,可能并不清楚ECMAScript与JavaScript之间的关系和区别。本文将深入探讨这两者的不同之处,并通过案例帮助大家更好地理解。 一、什么是ECMAScript? ECMAScript(简称ES)是一种脚本语言的标准,由ECMA国际组织制定。它定义了语言的语法、类型、语句、

Lua 脚本在 Redis 中执行时的原子性以及与redis的事务的区别

在 Redis 中,Lua 脚本具有原子性是因为 Redis 保证在执行脚本时,脚本中的所有操作都会被当作一个不可分割的整体。具体来说,Redis 使用单线程的执行模型来处理命令,因此当 Lua 脚本在 Redis 中执行时,不会有其他命令打断脚本的执行过程。脚本中的所有操作都将连续执行,直到脚本执行完成后,Redis 才会继续处理其他客户端的请求。 Lua 脚本在 Redis 中原子性的原因

msys2 minggw-w64 cygwin wsl区别

1 mingw-w64,这是gcc一直win平台下产生的,所以是win版的gcc,既支持32也支持64bit 2cygwin专注于原样在windows上构建unix软件, 3msys让Linux开发者在windows上运行软件,msys2专注于构建针对windows api构建的本机软件 4 wsl  windows subsystem for linux 是一个在windows 10 上能