Item 33:避免隐藏继承来的名称

本文探讨了C++中名称隐藏的问题,特别是当子类覆盖父类方法时如何避免隐藏父类其他重载方法。通过使用using声明或转发函数可以使父类方法重新变得可见。
Item 33: Avoid hiding inherited names.

其实本文的话题和继承完全没有关系,隐藏名称是作用域的问题。 在C++中每一对{ }都会开启一个新的作用域,并嵌套在当前作用域中。

一个示例

int x;
void func(){
    double x;
    cin>>x;     // read a new value for local x
}

可以看到double x隐藏了int x,因为C++的名称隐藏规则(name-hiding rules)隐藏的是名称,和类型无关!

继承作用域

子类可以访问父类中的名称,是因为子类的作用域是嵌套(nested in)在父类的作用域中的。 这一点也很符合直觉:

class Base{
public:
    void func_base();
};
class Derived{
public:
    void func_derived(){
        func_base();
    }
};

在func_derived()中调用func_base()时,编译器首先检查当前作用域内是否有名称func_base(当然C++是不允许在函数里定义函数的), 没有找到;然后去父作用域Derived中寻找名称func_base,仍然未找到;然后去再上一级作用域Base中寻找func_base,找到了!然后调用Base::func_base()。

如果还没找到,编译器还会去Derived所在命名空间下、全局作用域下寻找。

隐藏父类的名称

子类中重写(override)与父类方法同名的方法,将会隐藏父类中所有同名的重载方法。例如:

class Base{
public:
    virtual void func()=0;
    void func(int);
};
class Derived: public Base{
public:
    virtual void func();
};
...
Derived d;
d.func(1);      // Error!

Derived中声明的func方法,隐藏了父类中所有的func名称,包括所有的重载函数。

继承所有重载方法

当你从父类继承来了一系列的重载(overload)方法,而只想重写(override)其中的一个时,可以用using,否则其他重载方法会被隐藏。

class Derived: public Base{
public:
    using Base::func;
    virtual void func();
};
...
d.func(1);      // OK

继承一个重载方法

在public继承中,子类和父类是”is-a”的关系(见Item 32),所以通常我们希望从父类继承所有的方法。 但如果是private继承(见Item 39), 可能你只想要其中的一个,这时可以定义一个转发函数(forwarding function):

class Base{
public:
    virtual void mf1() = 0;
    virtual void mf1(int);
};
class Derived: private Base{
public:
    virtual void f1(){
        Base::mf1();        // 这是一个inline函数,见 Item30
    }
};

总结

  • 子类中的名称会隐藏父类中所有同名的属性。public继承表示这”is-a”的关系,应该避免这样做。
  • 使用using声明或者转发函数可以使父类名称再次可见。

转载地址:http://harttle.land/2015/09/06/effective-cpp-39.html
感谢作者 Harttle

import UIKit class OnlineChannelCardCell: UICollectionViewCell, GeneralListViewCellOverallDataSettable, SelectableView, BaseDeviceUIItem { lazy var isDeviceListOld: Bool = { return TPAppContextFactory.shared().isVmsDeviceListOldVersion }() typealias T = LDeviceChannel var collecAction: ((Bool, LDevice, LChannel) -> Void)? lazy var background = SelectionBackground() private lazy var channelView = CoverImageBigContainerView.createFromNib()! private lazy var infoContainer = ListCellDeviceInfoLabelContainer() private var supportEditDeviceConfigRemote: Bool{ get{ return TPSSAppContext.shared.currentRolePermission.deviceEditDeviceConfigRemote } } private var supportEditDeviceConfigLocal: Bool{ get { return TPSSAppContext.shared.currentRolePermission.deviceEditDeviceConfigLocal } } lazy var settingButton: UIButton = HorizontalLayoutResistantButton(type: .system) private var infoFieldContainerHeightConstraint: NSLayoutConstraint! private lazy var infoFieldBackground = UIView() override init(frame: CGRect) { super.init(frame: frame) contentView.backgroundColor = .tpbCard background.backgroundColor = .tpbCard contentView.addEqualSizeSubview(background) infoFieldBackground.translatesAutoresizingMaskIntoConstraints = false background.addSubview(infoFieldBackground) background.addEqualConstraints(view: infoFieldBackground, attributes: [.leading, .trailing, .top]) infoFieldContainerHeightConstraint = NSLayoutConstraint(item: infoFieldBackground, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 0, constant: 60) infoFieldContainerHeightConstraint.isActive = true let container = UIView(frame: .zero) container.translatesAutoresizingMaskIntoConstraints = false background.addSubview(container) NSLayoutConstraint(item: container, attribute: .leading, relatedBy: .equal, toItem: background, attribute: .leading, multiplier: 1, constant: 0).isActive = true NSLayoutConstraint(item: container, attribute: .trailing, relatedBy: .equal, toItem: background, attribute: .trailing, multiplier: 1, constant: -0).isActive = true NSLayoutConstraint(item: container, attribute: .bottom, relatedBy: .equal, toItem: background, attribute: .bottom, multiplier: 1, constant: 0).isActive = true NSLayoutConstraint(item: container, attribute: .top, relatedBy: .equal, toItem: infoFieldBackground, attribute: .bottom, multiplier: 1, constant: 0).isActive = true container.addEqualSizeSubview(channelView) infoFieldBackground.addSubview(infoContainer) infoContainer.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint(item: infoContainer, attribute: .leading, relatedBy: .equal, toItem: infoFieldBackground, attribute: .leading, multiplier: 1, constant: 16).isActive = true NSLayoutConstraint(item: infoContainer, attribute: .centerY, relatedBy: .equal, toItem: infoFieldBackground, attribute: .centerY, multiplier: 1, constant: 0).isActive = true settingButton.setBackgroundImage(TPImageLiteral("common_light_more_nor").fixSize(withWidth: 24), for: .normal) settingButton.contentMode = .scaleAspectFit let buttonContainer = OAStackView(arrangedSubviews: [settingButton]) buttonContainer.spacing = 8 buttonContainer.translatesAutoresizingMaskIntoConstraints = false infoFieldBackground.addSubview(buttonContainer) NSLayoutConstraint(item: buttonContainer, attribute: .trailing, relatedBy: .equal, toItem: infoFieldBackground, attribute: .trailing, multiplier: 1, constant: -12).isActive = true NSLayoutConstraint(item: buttonContainer, attribute: .centerY, relatedBy: .equal, toItem: infoFieldBackground, attribute: .centerY, multiplier: 1, constant: 0).isActive = true NSLayoutConstraint(item: buttonContainer, attribute: .leading, relatedBy: .equal, toItem: infoContainer, attribute: .trailing, multiplier: 1, constant: 8).isActive = true } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } func apply(_ item: LDeviceChannel, at indexPath: IndexPath) { self.indexPath = indexPath if let channel = item.channel { // NVR Channel channelView.nvrChannelNameContainer.isHidden = false channelView.nvrChannelNameLabel.text = channel.name channelView.collectAction = { [weak self] (isCollected) in self?.doCollectAction(isCollected, item.device, channel) } channelView.configure(channel: channel, nvr: item.device, size: .extraLarge, isCard: true, folded: false) infoFieldContainerHeightConstraint.constant = 0 infoFieldBackground.isHidden = true } let appContext = TPAppContextFactory.shared() if appContext.isVmsLogin { if isDeviceListOld { if appContext.isLogin && item.device.listType == .remote{ settingButton.isHidden = true } } else { //新体系下,判断是否有本地修改设备设置的权限 let accessLocal: Bool = supportEditDeviceConfigLocal && TPSSAppContext.shared.localDeviceMac.contains(item.channel?.mac ?? "") settingButton.isHidden = ((item.channel?.vmsRoleType != .admin && TPSSAppContext.shared.isVmsRolePermissionOldVersion) || (!(supportEditDeviceConfigRemote || accessLocal) && !TPSSAppContext.shared.isVmsRolePermissionOldVersion) ) && appContext.isVmsLogin && item.device.listType != .local } } } private func doCollectAction(_ collect: Bool, _ device: LDevice, _ channel: LChannel) { collecAction?(collect, device, channel) } override func layoutSubviews() { super.layoutSubviews() var bp1: UIBezierPath? = nil let cornerRaduis: CGFloat = kBorderRadius //四个圆角 bp1 = UIBezierPath.init(roundedRect: bounds, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: cornerRaduis, height: cornerRaduis)) if indexPath.row == 0 { if bp1 != nil{ let maskLayer = CAShapeLayer.init() maskLayer.path = bp1?.cgPath background.layer.mask = maskLayer } //底下两圆角 var bp2: UIBezierPath? = nil bp2 = UIBezierPath.init(roundedRect: bounds, byRoundingCorners: [.bottomLeft, .bottomRight], cornerRadii: CGSize(width: cornerRaduis, height: cornerRaduis)) if bp2 != nil{ let maskLayer = CAShapeLayer.init() maskLayer.path = bp2?.cgPath self.layer.mask = maskLayer } } else { if bp1 != nil{ background.layer.mask = nil let maskLayer = CAShapeLayer.init() maskLayer.path = bp1?.cgPath self.layer.mask = maskLayer } } } }
10-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值