【问题标题】:Calling different child class function from the same parent invocation从同一个父调用中调用不同的子类函数
【发布时间】:2018-01-23 21:48:40
【问题描述】:

考虑这个简单的 C++11 继承示例:

class A
{
public:
    virtual void func() = 0;
};

class B : public A
{
public:
    void func() { func1(); /* Wish this could be func1() or func2()! */ };

    void func1() { /* Does one thing */ };
    void func2() { /* Does another thing */ };
};

void doSomeStuff(A &a) 
{
    a.func();
}

int main()
{
    B b;

    doSomeStuff(b);

    return 0;
}

我正在努力做到这一点,这样我就不必修改(或复制)类 A 的定义或函数 doSomeStuff,但我希望调用 a.func() 来调用 func1() 或 func2 B 的 ()。理想情况下,我会将行 doSomeStuff(b) 更改为 doSomeStuff(b.butWithFunc1),但我也可以通过某种方式修改 B 的 func() 版本,以便它可以在内部决定调用 @ 987654325@ 或 func2 基于某些参数。

在调用func 期间,B 类型的同一对象有时可能必须调用func1func2,因此我不能使用B 类的持久成员来决定。向 func() 添加一个参数也会使这变得微不足道,但这也不是我能做的。

我有点想知道是否有某种方法可以向 B 类添加一个函数,该函数返回 B 类的突变版本,该版本从 func() 调用 func2(),或者我是否可以使用函数指针或其他东西玩一些技巧.然而,有些事情告诉我我做错了,显而易见的解决方案是盯着我的脸。

如果它对上下文有帮助,A 类类似于 std::lock_guard,它适用于信号量和互斥锁(对于它们只有一种锁定和解锁的定义),但本例中的 B 类是一个 R/W 锁 - 所以有一个“readLock”和“writeLock”,我想能够说“自动锁定这个 RW 锁作为一个读锁”,而不必复制/破坏自动锁代码。

例如:

{
    A_AutoSem(myMutex); // calls lock() on myMutex
    //... do some stuff

    // end of the block, ~A_AutoSem calls unlock on myMutex
}

{
    A_AutoSem(B_RWLock); // how do I say here "call readLock"?
    // ... do some stuff

    // end of the block ~A_AutoSem should call "readUnlock" on B_RWLock
}

【问题讨论】:

  • 那很模糊。 func1func2 都没有做任何事情,不清楚为什么不能使用 B 的成员。
  • 什么样的逻辑决定了在func1()func2() 之间进行选择的“有时”部分?我真的不明白为什么跟踪某些状态的简单条件和成员值不起作用。
  • @melpomene,也许考虑 RW 锁作为上下文会有所帮助。我不能使用 B 的成员,因为可能有 2 个线程使用 B 并且一个想同时锁定为读,另一个锁定为写。
  • 为什么这些线程会使用相同的代码?
  • 我添加了一个更具体的例子,也许这将有助于理解约束。

标签: c++


【解决方案1】:

只需定义一些额外的类来调用func1()func2(),然后将这些类传递给doSomeStuff(),而不是直接传递B

试试这样的:

class A
{
public:
    virtual void func() = 0;
};

class B
{
public:
    void func1() { /* Does one thing */ };
    void func2() { /* Does another thing */ };
};

class C1 : public A
{
private:
    B &m_b;
public:
    C1(B &b) : m_b(b) {}
    void func() override { m_b.func1(); }
};

class C2 : public A
{
private:
    B &m_b;
public:
    C2(B &b) : m_b(b) {}
    void func() override { m_b.func2(); }
};

void doSomeStuff(A &a) 
{
    a.func();
}

int main()
{
    B b;

    {
    C1 c(b);
    doSomeStuff(c);
    }

    {
    C2 c(b);
    doSomeStuff(c);
    }

    return 0;
}

Live Demo

或者:

class A
{
public:
    virtual void func() = 0;
};

class B
{
private:
    void func1() { /* Does one thing */ };
    void func2() { /* Does another thing */ };

public:
    class C1 : public A
    {
    private:
        B &m_b;
    public:
        C1(B &b) : m_b(b) {}
        void func() override { m_b.func1(); }
    };

    class C2 : public A
    {
    private:
        B &m_b;
    public:
        C2(B &b) : m_b(b) {}
        void func() override { m_b.func2(); }
    };
};

void doSomeStuff(A &a) 
{
    a.func();
}

int main()
{
    B b;

    {
    B::C1 c(b);
    doSomeStuff(c);
    }

    {
    B::C2 c(b);
    doSomeStuff(c);
    }

    return 0;
}

Live Demo

【讨论】:

  • @Remy Lebeau, Curious:不知道这也能做到stackoverflow.com/questions/16913754/…
  • @MohammadKanan:“我正在努力做到这一点,这样我就不必修改(或复制)A 类的定义或函数 doSomeStuff”。指定调用哪个方法需要修改doSomeStuff,这是 OP 不想要的。
  • 啊,是的。看到您的解决方案让我意识到问题是我的 B 类实际上并不是 A 的子类 - 您的 C 确实是 A 的子类,并调整 B 以适应其模型。感谢您的帮助!
猜你喜欢
  • 2020-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多