我应该如何声明我的对象才能正确使用这些功能?

时间:2019-04-06 12:25:15

标签: c++

如果有人能启发我,我将不胜感激:说我声明以下内容:

class A{
public:
    friend class A1;
}

class A1{
public:
    void f(A* a) { cout<<"Base"; };
}

class B : public A{
public:
    friend class B1;
}

class B1 : public A1{
public:
    void f(B* b) { cout << "Derived"; };
}

当我声明我的对象时,我这样做:

A* a;
A1* a1;
if (condition1) {
    a = new A;
    a1 = new A1;
}
else {
    a = new B;
    a1 = new B1;
}
a1 -> f(a); //outputs always 'base'

如何基于a1 -> f(a)使B1::f()输出condition1? 注意:这只是我的代码的一小部分,并且类的结构必须保持不变。

1 个答案:

答案 0 :(得分:1)

如果您希望自动完成正确的通话,则需要为 f 拥有相同的签名,并使其具有 virtual friend >没用

#include <iostream>
using namespace std;

class A {
};

class A1{
public:
    virtual void f(A* a) { cout<<"Base" << endl; };
};

class B : public A{
};

class B1 : public A1{
public:
    virtual void f(A* b) { cout << "Derived" << endl; };
};

int main(int argc, char **)
{
  A* a;
  A1* a1;

  if (argc == 1) {
    a = new A;
    a1 = new A1;
  }
  else {
    a = new B;
    a1 = new B1;
  }
  a1 -> f(a); 
}

编译和执行:

pi@raspberrypi:/tmp $ g++ c.cc
pi@raspberrypi:/tmp $ ./a.out
Base
pi@raspberrypi:/tmp $ ./a.out 1
Derived
pi@raspberrypi:/tmp $ 

在接收器的真实类型为 virtual 的情况下确定调用方法,参数的真实类型无关紧要,仅考虑签名


如果您需要检查 B1 :: f 的参数是 B * ,则可以执行以下操作:

#include <iostream>
using namespace std;

class A {
  public:
    virtual ~A(){}
};

class A1{
  public:
    virtual void f(A* a) { cout<<"Base" << endl; };
};

class B : public A{
  public:
    virtual ~B(){}
};

class B1 : public A1{
  public:
    virtual void f(A* b) {
      cout << "Derived, " 
        << ((dynamic_cast<B*>(b) == NULL) 
           ? "invalid call, needed a B*"
           : "valid call with a B*")
         << endl;
    }
};

int main(int argc, char **)
{
  A* a;
  A1* a1;

  switch (argc) {
  case 1:
    a = new A;
    a1 = new A1;
    break;
  case 2:
    a = new B;
    a1 = new B1;
    break;
  default:
    a = new A;
    a1 = new B1;
  }

  a1 -> f(a); 
}

编译和执行:

pi@raspberrypi:/tmp $ g++ c.cc
pi@raspberrypi:/tmp $ ./a.out
Base
pi@raspberrypi:/tmp $ ./a.out 1
Derived, valid call with a B*
pi@raspberrypi:/tmp $ ./a.out 1 2
Derived, invalid call, needed a B*

我在A和B中添加了虚拟析构函数,以便能够使用dynamic_cast

或者如果您想在 B1 :: f 的参数不是 B * 的情况下使用基本情况:

class B1 : public A1{
  public:
    virtual void f(A* a) {
      B * b = dynamic_cast<B*>(a);

      if (b == NULL)
        A1::f(a);
      else {
        cout << "Derived" << endl;
        // use of b known as a B*
      }
   }
};

编译和执行:

pi@raspberrypi:/tmp $ g++ c.cc
pi@raspberrypi:/tmp $ ./a.out
Base
pi@raspberrypi:/tmp $ ./a.out 1
Derived
pi@raspberrypi:/tmp $ ./a.out 1 2
Base