从具有相同基的另一个派生类调用派生类的非常量方法

Posted

技术标签:

【中文标题】从具有相同基的另一个派生类调用派生类的非常量方法【英文标题】:Calling non-const method of a derived class from another derived class having the same base 【发布时间】:2017-05-09 20:12:18 【问题描述】:

我有一些基类和两个派生自它的类。我想为第一个派生类编写一个方法,通过调用第二个派生类的现有方法来修改对象的内部数据。我想要这样做是为了避免创建包含我已经为第二个派生类编写的相同代码行的方法。

有没有一种安全的方法来做这样的事情? 目前,我这样做的方式是这样的:

class Base

protected:
    int data;
// some public methods
;

class Derived1: public Base

private:
    void ModifyData1()  data = 1; 
// some public methods
friend class Derived2;
;

class Derived2: public Base

public:
    void ModifyData2()
    
        (static_cast<Derived1 *>((Base*)this))->Derived1::ModifyData1();
    
;

所以按照我的理解,指针this 被隐式转换为基指针(向上转换),然后在该指针上执行static_cast,向下转换为Derived1 类。这会修改对象的私有变量data,即使我们调用了另一个派生类的方法。

代码似乎可以工作,但我在这里感觉不安全,特别是因为带有dynamic_cast 的版本会导致分段错误。感谢您的建议!

更新:我在 Linux 中使用 GCC。

【问题讨论】:

这只似乎有效。让我用动物术语解释一下你有什么。基类是哺乳动物,派生类是猫和狗。你正在做的实际上是试图把猫变成狗,这是行不通的。 听起来方法应该在基类中 这违反了别名。它是否“有效”可能是可以观察到的,但它不是按语言可定义的。这会调用未定义的行为。如果您有一个应该可以通过某个 Base 的派生(而不是多个)访问的工作流,那么该行为属于该 Base,而不是像这样被破解。 这有点过时(WhiZTiM 已经正确回答了你的问题),但我在godbolt's compiler explorer 尝试了每个版本的 gcc,每个版本都给我一个编译器错误 - 对于 clang 和VC++。你一定在做一些不同的事情。 MikeMB 抱歉,我忘了在上面的代码中添加以下两件事: (Base*) 和命名空间标识符 Derived1:: 。这两个让我编译。我已经更新了代码。 【参考方案1】:

您使用此代码调用了未定义的行为:

void ModifyData2()

    (static_cast<Derived1 *>(this))->ModifyData1();

因为this 指针不是Derived1*Derived1 也不是其值类型Derived2 的基数。


我想要这个是为了避免制作包含相同内容的方法 我已经为第二个派生类编写的代码行。

你为什么不把那个方法带到基类呢?如果您不想这样做(可能是因为它不是所有派生类型的整体属性),您可以使用一个额外的派生类,Derived1Derived2 都将从中继承。


class Base

protected:
    int data;
    // some public methods
;

class DerivedModifier : Base

protected:
    virtual void ModifyData()  data = 1; 
;

class Derived1: public DerivedModifier 

private:
     void ModifyData1()
        DerivedModifier::ModifyData();
    
;

class Derived2: public DerivedModifier 

public:
    void ModifyData2()
        DerivedModifier::ModifyData();
    
;

【讨论】:

非常感谢!在我发布问题后不久,它让我感到震惊,我可以将方法放在基类中来解决我的问题,即使它不是一个完全“整体”的属性。然后我回到这里,看到了你同样的建议。【参考方案2】:

修改data的方法应该和data放在同一个类中。父类持有data,它也应该持有modifyData()

class Base 
public:
    void modifYData()  data = 1
    // some other public methods
private:
    int data;
;

您将能够执行以下操作:

Base b;
Derived1 d1;
Derived2 d2;

b.modifyData();
d1.modifyData();
d2.modifyData();

如果您希望派生类在调用 modifyDtata() 时表现不同,请将方法设为虚拟并在其中覆盖它。

注意:阅读encapsulation 和access specifiers。

【讨论】:

以上是关于从具有相同基的另一个派生类调用派生类的非常量方法的主要内容,如果未能解决你的问题,请参考以下文章

如何在具有相同函数名的派生类中调用基类的函数[重复]

当您在具有相同基类的派生类之间进行动态转换时会发生啥?

是否有可能有一个基类方法调用其所有派生类的相同(但被覆盖的方法)?

具有共同属性但值不同的派生类的正确设计设置

将shared_ptr的向量复制到抽象基的派生类中。

派生类调用使用非继承成员的继承函数