槽的继承

本文详细解释了在类继承过程中遇到的同名槽和初始化参数处理机制,包括如何解决基类中同名槽的冲突、初始化参数的优先级选择,以及访问器方法的选择策略。通过实例演示了槽组合、初始化参数合并、读写操作等关键概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

槽和继承

根据字面含义,他是为了解决当进行类的继承的时候出现的槽名字/槽描述符一样时子类如何继承和取舍。

(defparameter *account* (make-instance 'bank-account))                    

因为一个类中槽的名字必须是唯一的,虽然这样,但是如果一个类继承了很多的基类,但是这些基类都定义了一个叫balance的槽。处理方式是把同名描述符放到一块,然后去一个唯一的名字(我感觉仍旧是叫balance

:initform 因为每个类都会指定默认值,新类将使用最相关的那一个。

:initargs 他不需要互斥,就好比一个槽可以有很多个别名来指向他,新的槽描述符将会包含所有的:initargs,make-instance可以调用任何任何一个:initargs来给他赋值。如果有很多个:initargs对同一个槽赋值的话,会使用make-instance中最左边的那个。

When an instance would inherit a slot with the same name from several of its superclasses, the instance inherits a single slot that combines the properties of the slots in the superclasses. The way combination is done varies from propertyto property:

1. The : allocation, :initform(ifany), and :documentation (if any), will be those of the most specific classes.

2. The :initargs will be the union of the :initargs of all the superclasses. So will the .-accessors, : readers, and : writers, effectively.

3. The : type will be the intersection of the : types of all the superclasses.

一个类中:initarg/:accessor 后参数名字一样,如何处理?

accessor后面一样的函数名一样的时候,如果调用的话,它会选择最下面的那个。Accessor后面跟的是一个函数名,比如我们可以(the-b *Q*)

CL-USER> (defclass par()
	  		 ((b :initarg :b :initform "b" :accessor the-b)
	   		 (a :initarg :a :initform "a" :accessor the-b)))
#<STANDARD-CLASS PAR>
CL-USER> (defparameter *q* (make-instance 'par)) *Q*
CL-USER> (the-b *Q*)                             "a"
CL-USER> (setf (the-b *q*) 4)                     4
CL-USER> (slot-value *q* 'a)                      4
CL-USER> (slot-value *q* 'b)                     "b"

当父类与子类中的:accessor重复时,如果调用的话,他会返回最相关的那个方法进行处理。

CL-USER> (defclass too-3()
	   ((a :initarg :a-1 :initform "a" :accessor a-a)
	    (b :initarg :b-1 :initform "b" :accessor b-b)))
#<STANDARD-CLASS TOO-3>
CL-USER> (defclass sub-too-3(too-3)
	   ((a :initarg :a-2 :initform "a3" :accessor b-b)
	    (b :initarg :a-1 :initform "b3" :accessor b-b2)))
#<STANDARD-CLASS SUB-TOO-3>
CL-USER> (defparameter *kk* (make-instance 'sub-too-3))  *KK*
CL-USER> (b-b *kk*)                                      "a3"

下面是如果把initarg后的形参关键字设置为一样的时候,比如都叫:b的话,你只需要设置一个:b,就可以关联到所有initarg:b的槽。

CL-USER> (defclass par()
	  		 ((b :initarg :b :initform "b" :accessor the-b)
	   		 (a :initarg :b :initform "a" :accessor the-b)))
#<STANDARD-CLASS PAR>
CL-USER> (defparameter *t* (make-instance 'par :b "me"))  *T*
CL-USER> (slot-value *t* 'a)                              "me"
CL-USER> (slot-value *t* 'b)                              "me"

如果父类跟子类中的不同槽的:initarg参数一样,跟上面一样,全部初始化。

CL-USER> (defclass too-2()
	  		 ((a :initarg :a-1 :initform "a" :accessor a-a)
	 		 (b :initarg :b-1 :initform "b" :accessor b-b)))
#<STANDARD-CLASS TOO-2>
CL-USER> (defclass sub-too-2(too-2)
	   		((a :initarg :a-2 :initform "a" :accessor b-b)
	 	     (b :initarg :a-1 :initform "b" :accessor b-b2)))
#<STANDARD-CLASS SUB-TOO-2>
CL-USER> (defparameter *uu* (make-instance 'sub-too-2 :a-1 "p"))  *UU*
CL-USER> (b-b2 *uu*)                                              "p"
CL-USER> (a-a *uu*)                                               "p"

下图是,当你初始化时,光标放到类后时所指示你可以进行初始化的initargs参数。



<think>嗯,用户问的是Qt的信号和能否被继承。首先,我得回忆一下Qt的信号和机制的基本原理。信号和是Qt的核心特性,用于对象之间的通信。信号在类中声明,当某个事件发生时被发射,而则是用来接收和处理这些信号的函数。 接下来要考虑继承的概念。在C++中,派生类会继承父类的成员函数和变量,但信号和是否属于可继承的范畴呢?根据Qt的文档,信号和本身是类的成员函数,所以理论上应该遵循C++的继承规则。也就是说,如果一个类继承自拥有信号或的基类,那么派生类会继承这些信号和。 不过,这里可能有一些细节需要注意。比如,信号在基类中声明后,是否可以在派生类中发射?答案是肯定的,派生类可以发射基类的信号。但信号的实现是由moc(元对象编译器)生成的,所以即使信号在基类中声明,派生类也可以使用它们。 对于函数,如果基类有一个,派生类可以重写这个,前提是基类的被声明为虚函数。否则,如果只是普通函数,派生类中的同名会隐藏基类的,可能导致预期外的行为。因此,正确使用虚函数关键字对于继承和重写非常重要。 另外,Qt5引入了新的信号和语法,允许使用函数指针或Lambda表达式进行连接,这可能会影响继承时的使用方式。比如,在派生类中重写基类的时,需要确保连接方式正确,特别是在使用新语法的情况下。 还要考虑元对象系统的影响。因为Qt的信号和依赖于元对象系统,任何派生类都必须在其定义中使用Q_OBJECT宏,这样才能正确继承和扩展基类的信号和。如果忘记添加这个宏,可能会导致信号和无法正常工作。 可能存在的误区是认为信号不能被重写。实际上,信号不能被重写,只能在派生类中发射基类的信号。而函数如果声明为虚函数,则可以重写,以便在派生类中提供不同的实现。 总结一下,Qt的信号和可以被继承,但需要注意基类中信号和的声明方式,以及派生类中的正确使用,包括是否需要重写函数,确保元对象系统的正确配置等。这样才能保证信号和继承体系中的有效运作。</think>Qt的信号和机制支持继承特性,以下是逐步说明: 1. **信号的可继承性** - 基类中定义的信号会被所有派生类自动继承。 - 派生类可以直接发射基类信号(无需重新声明)。 - 例: ```cpp class Base : public QObject { Q_OBJECT signals: void baseSignal(); }; class Derived : public Base { // 可以直接发射baseSignal() }; ``` 2. **的可继承性** - 基类函数默认可以被派生类继承 - 需要重写时: ```cpp class Base : public QObject { Q_OBJECT public slots: virtual void baseSlot() { /* 基类实现 */ } }; class Derived : public Base { public slots: void baseSlot() override { /* 派生类重写 */ } }; ``` 3. **连接注意事项** - 当使用新式连接语法时: ```cpp QObject::connect(sender, &Base::baseSignal, receiver, &Derived::baseSlot); ``` - 这种写法支持多态调用,会正确调用派生类重写的 4. **特殊继承规则** - 信号不允许重定义(不能在派生类中重新声明基类同名信号) - 虚函数需要显式声明`virtual`关键字 - 元对象系统要求:所有继承QObject的类必须包含Q_OBJECT宏 5. **使用建议** - 对于需要多态行为的,声明为虚函数 - 避免在派生类中定义与基类同名的信号 - 通过`qobject_cast`进行安全的类型转换 结论:Qt的信号和支持完整的继承机制,但需要遵循C++继承规则和Qt元对象系统的特殊要求,合理使用虚函数和多态特性可实现灵活的对象间通信。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值