假设我有两个结构a
和b
,每个结构中都包含几个变量(大多数变量是c ++核心类型,但不是全部)。
有没有办法创建一个名为c
的指针,它可以指向其中任何一个?或者,有没有办法创建一个可以容纳其中任何一个的集合?
由于
答案 0 :(得分:4)
或者,有没有办法创建一个可以容纳任何一个的集合 他们?
查看Boost.Any和Boost.Variant。如果您只有2个课程,那么variant
就足够了。如果您计划其他类型,并且不想重新编译此“设置”,请使用any
。
然后使用any
或variant
的任何容器。
#include <boost/any.hpp>
#include <boost/variant.hpp>
#include <vector>
class A { };
class B { };
class C { };
int main()
{
// any
std::vector<boost::any> anies;
anies.push_back(A());
anies.push_back(B());
A a0 = boost::any_cast<A>(anies[0]);
A b0 = boost::any_cast<A>(anies[1]); // throws boost::bad_any_cast
// variant
std::vector<boost::variant<A,B> > vars;
vars.push_back(A());
vars.push_back(B());
A a1 = boost::get<A>(vars[0]);
A b1 = boost::get<A>(vars[1]); // throws boost::bad_get
// and here is the main difference:
anies.push_back(C()); // OK
vars.push_back(C()); // compile error
}
编辑:variant
当然也可以拥有2个以上的课程。但扩展variant
以便能够在不重新编译的情况下保留新的未预料到的类型。
答案 1 :(得分:3)
如果 和 b 无关,那么您可以使用void*
或更好的提升 {{1输入。
如果 是 b 的超类,则可以使用any
代替。
答案 2 :(得分:3)
创建指向两者中任何一个的指针的常用方法是使它们从公共基类继承。基类的任何指针都可以指向任何子类。请注意,这样您只能通过该指针访问属于基类的元素:
class Base {
public:
int a;
};
class Sub1 : public Base {
public:
int b;
};
class Sub2 : public Base {
public:
int c;
};
int main() {
Base* p = new Sub1;
p.a = 1; // legal
p.b = 1; // illegal, cannot access members of sub-class
p = new Sub2; // can point to any subclass
}
您要实现的目标称为polymorphism,它是面向对象编程的基本概念之一。访问子类成员的一种方法是向下转换指针。执行此操作时,必须确保将其强制转换为正确的类型:
static_cast<Sub1*>(p).b = 1; // legal, p actually points to a Sub1
static_cast<Sub2*>(p).c = 1; // illegal, p actually points to a Sub1
关于你的第二个问题,使用上述技术,你可以创建一组指向基类的指针,然后可以保存任何子类的实例(这些也可以混合使用):
std::set<Base*> base_set;
base_set.insert(new Sub1);
base_set.insert(new Sub2);
答案 3 :(得分:1)
如果他们都从相同的类型继承你可以做到。这就是OOP框架如何工作,所有类都继承自Object。
答案 4 :(得分:0)
只需定义一个公共超类C和C的两个子类A,B。如果A和B没有公共结构(没有公共属性),则可以将C保留为空。
定义:
A *a = new A();
B *b = new B();
C *c;
然后你可以做到两个
c = a;
或
c = b;
答案 5 :(得分:0)
虽然你能做到这一点,那指针意味着什么?如果您的应用程序的任何部分抓住指向“a
或b
”的指针,除非您提供额外的类型信息,否则它不能用它做很多事情。
提供额外的类型信息将导致客户端代码,如
if( p->type == 'a' ) {
... a-specific stuff
} else if( p->type == 'b' ) {
... b-specific stuff
} ...
哪个不是很有用。
最好将'type-specificness'委托给对象本身,这是面向对象设计的本质,而C ++有一个非常好的类型系统。
class Interface {
public:
virtual void doClientStuff() = 0; //
virtual ~theInterface(){};
};
class A : public Interface {
virtual void doClientStuff(){ ... a-specific stuff }
};
class B : public Interface {
virtual void doClientStuff(){ ... b-specific stuff }
};
然后你的客户端代码将变得更加不知道,因为类型切换是由C ++为你完成的。
void clientCode( Interface* anObject ) {
anObject->doClientStuff();
}
Interface* i = new A();
Interface* j = new B();
clientCode( i );
clientCOde( j );
答案 6 :(得分:0)
有几种方法可以做到这一点:
由于其他人已经描述了前三个选项,我将描述第四个选项。基本上,有区别的容器使用union
类型来使用单个对象的存储来存储多个不同值中的一个。通常,这样的并集与枚举或整数类型一起存储在结构中,用于区分当前在联合类型中保存的值。举个例子:
// Declarations ...
class FirstType;
class SecondType;
union PointerToFirstOrSecond {
FirstType* firstptr;
SecondType* secondptr;
};
enum FIRST_OR_SECOND_TYPE {
FIRST_TYPE,
SECOND_TYPE
};
struct PointerToFirstOrSecondContainer {
PointerToFirstOrSecond pointer;
FIRST_OR_SECOND_TYPE which;
};
// Example usage...
void OperateOnPointer(PointerToFirstOrSecondContainer container) {
if (container.which == FIRST_TYPE) {
DoSomethingWith(container.pointer.firstptr);
} else {
DoSomethingElseWith(container.pointer.secondptr);
}
}
请注意,在下面的代码中,“firstptr”和“secondptr”实际上是同一个变量的两个不同视图(即相同的内存位置),因为联合会为其内容共享空间。
请注意,即使这是一个可能的解决方案,我也不会推荐它。这种事情不是很容易维护。我强烈建议尽可能使用继承。
答案 7 :(得分:0)
抽象类!!!! - 简单的解决方案
拥有一个可用作指向多个派生子类的指针的基类。 (不需要铸造)
当您在其中使用虚拟方法时,将定义抽象类。然后在子类中实现这个方法......简单:
// abstract base class
#include <iostream>
using namespace std;
class Polygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area (void) =0;
};
class Rectangle: public Polygon {
public:
int area (void)
{ return (width * height); }
};
class Triangle: public Polygon {
public:
int area (void)
{ return (width * height / 2); }
};
int main () {
Polygon * ppoly1 = new Rectangle (4,5);
Polygon * ppoly2 = new Triangle (4,5);
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
cout << ppoly1->area() << '\n';
cout << ppoly2->area() << '\n';
return 0;
}