【问题标题】:c++ typecast base ptr to derived ptr held in a reference classc ++ typecast base ptr到引用类中保存的派生ptr
【发布时间】:2017-08-14 22:17:53
【问题描述】:

我正在尝试创建一个对象引用模板类,它将保存类指针并且一切正常,除非尝试将基类 ptr 类型转换为派生类 ptr。

代码如下:

#include <stdio.h>
#include <stdlib.h>

#define null nullptr

class BaseType;
class DerivedType;

template<class T>
class ObjRef {
public:
  T *ptr = null;  //should be private

  ObjRef& operator= (T *ptr) { this->ptr = ptr; return *this; }
  ObjRef& operator= (const ObjRef &ref) { ptr = ref.ptr; return *this; }
  operator T*() const {return ptr;}
  operator T() const {return *ptr;}
  ObjRef() {}
  ObjRef(const ObjRef &copy) { ptr = copy.ptr; }
#ifdef VOID_FIX
  ObjRef(void*p) { ptr = (T*)p; }  //this could fix the bug except would not work with multiple inheritance and is not safe
#else
  ObjRef(T*p) { ptr = p; }
#endif
  ~ObjRef() { }
  T* operator->() const {return ptr;}  //unfortunately operation. (dot) can not be overloaded - that would make life too easy :(
};

class Object {};

class BaseType : public Object {
public:
  int baseValue;
};

class DerivedType : public BaseType {
public:
  operator BaseType*() {return (BaseType*)this;}  //helpful?
  int derivedValue;
};

typedef ObjRef<BaseType> Base;
typedef ObjRef<DerivedType> Derived;

void func4(Base x) {
  x->baseValue = 1;
}

void func5(Derived x) {
  x->derivedValue = 1;
}

int main() {
  Base b = null;
  Derived d = null;
  Base x;

  x = d;  //no type cast needed
  func4((Base)d);  //cast from Derived to Base class - no problem

  b = d;  //base does point to derived
//  func5((Derived)b);  //cast from Base to Derived - does not work (desired syntax)
  // with gcc -fpermissive can be used to change error to warning - can I silence the warning ?
  // what would cl.exe equivalent be?

//  func5((Derived)b.ptr);  //invalid cast, ptr should be private
//  func5((DerivedType*)b);  //invalid cast, ptr should be private
//  func5(dynamic_cast<DerivedType*>(b.ptr));  //invalid cast, source type is not polymorphic, ptr should be private

  func5((DerivedType*)b.ptr);  //this works but is undesired and ptr should be private
  func5(static_cast<DerivedType*>(b.ptr));  //works but again is undesired and ptr should be private

  return 0;
}

在示例中,ObjRef 是一个模板,它包含一个指向已定义类的指针,并用作新类型。除了尝试将基类转换为派生类外,它工作正常。查看如何使用基类引用调用 func5()。第一次尝试是所需的语法。如果我在引用类中使用 ptr,它会起作用,但这是不希望的。

我只是觉得我缺少一个接线员之类的东西。

谢谢。

【问题讨论】:

  • 你的代码中有很多被误导的东西。 #define null nullptr 不要那样做。 operator BaseType*() {return (BaseType*)this;} 完全没用;使用static_cast&lt;BaseType*&gt;(&amp;myObject)。您继续使用 C 风格的演员表进行转换;使用 C++ 风格的演员表。最后,ObjRef 似乎完全不需要。
  • @Bo - 如果基类指针指向派生类,则可以。即使有多重继承也是可能的,但不明智。
  • @Peter - 好的,你欺骗了我,隐藏了指针类型的 * 并使 Derived 不是从 Base 派生的。

标签: c++ inheritance casting


【解决方案1】:

像往常一样,我在发布后不久就找到了解决方案。
ObjRef 类需要知道基类。 这是新代码:

#include <stdio.h>
#include <stdlib.h>

#define null nullptr

class BaseType;
class DerivedType;

template<class T>
class ObjRef {
public:
  T *ptr = null;

  ObjRef& operator= (auto *ptr) { this->ptr = ptr; return *this; }
  ObjRef& operator= (const ObjRef<auto> &ref) { ptr = ref.ptr; return *this; }
  operator T*() const {return ptr;}
  ObjRef() {}
  ObjRef(const ObjRef<auto> &copy) { ptr = (T*)copy.ptr; }
  ObjRef(T*p) { ptr = p; }
  ~ObjRef() { }
  T* operator->() const {return ptr;}  //unfortunately operator. (dot) can not be overloaded - that would make life too easy :(
};

class Object {};

class BaseType : public virtual Object {
public:
  int baseValue;
};

class InterfaceType : public virtual Object {
public:
  virtual void func7() {
    printf("it works!\n");
  };
};

typedef ObjRef<InterfaceType> Interface;

class DerivedType : public BaseType, public InterfaceType {
public:
  int derivedValue;
};

typedef ObjRef<BaseType> Base;
typedef ObjRef<DerivedType> Derived;

void func4(Base x) {
  x->baseValue = 1;
}

void func5(Derived x) {
  x->derivedValue = 2;
}

void func6(Interface x) {
  x->func7();
}

int main() {
  Base b = new BaseType();
  Derived d = new DerivedType();
  Base x;

  x = d;  //no type cast needed
  func4((Base)d);  //cast from Derived to Base class - no problem
  printf("BaseValue=%d\n", d->baseValue);

  b = d;  //base does point to derived
  func5((Derived)b);  //cast from Base to Derived - works now!
  printf("DerivedValue=%d\n", d->derivedValue);

  func6(d);

  return 0;
}

更新:发布了一个新版本,可以使用任何级别的继承,但现在需要 C++14(自动关键字)

更新 #2:现在使用单个 ObjRef 类(仍然需要 C++14)。不幸的是 cl.exe 还不支持“自动”模板参数:(

更新 #3:添加了一些测试代码来证明它有效。

【讨论】:

  • 当然不是,里面只有空值。为什么它不起作用?
  • 好的,用一些真实的测试值更新它,就像一个魅力。需要 gcc 5.0 (C++14)。还不能与 cl.exe 一起使用(来吧 M$ 与时俱进!)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-04-28
  • 1970-01-01
  • 2011-10-01
  • 1970-01-01
  • 2016-05-20
  • 1970-01-01
相关资源
最近更新 更多