我在CPP和Java中都有一个问题。
#include <vector>
class A {};
class B : A {};
int main()
{
std::vector<A> a;
std::vector<B> b;
a = b; // compiler error
}
由于某些原因,这两个向量不兼容;
详细信息编辑
感谢所有答案。我需要指出,上面的示例是问题的简化版本,不与细节混淆。我真正的问题是一个Java项目,其中我使用包装器类在两个变量之间保持引用连接。
Printable.java
package ConsoleGraphics;
public class Printable { /** code */ }
StringPrintable.java
package ConsoleGraphics;
public class StringPrintable { /** code */}
Iterator.java
package Jav.util;
public abstract
class Iterator<T> implements java.util.Iterator<T>
{ /** code */ }
Copy_Iter.java
package Jav.util;
// An Iterator keeping deep copies of elements
public class Copy_Iter<T> extends Iterator<T>
{ /** code, defines abstract methods */ }
Ref_Iter.java
package Jav.util;
// Iterator keeping references of the elements.
public class Ref_Iter<T> extends Iterator<T>
{ /** code, defines abstract methods */ }
Box.java
package Jav.util;
public class Box<T> extends Copy_Iter<T>
{ /** code */ }
RefBox.java
package Jav.util;
public class RefBox<T> extends Ref_Iter<T>
{ /** code */ }
Screen.java
package ConsoleGraphics;
// This class creates my problem
public class Screen
{
// data members
private Jav.util.RefBox<Printable> p1;
private Jav.util.RefBox<
Jav.util.Box <Printable> >p2;
/** ctors and methods */
// METHOD OF CONCERN
// As you can see this function accepts a
// Box containing Printable. If I try to feed it a
// Box containing StringPrintable I fail. But if I
// create a seperate method for StringPrintable
// That would mean creating a separate method
// for every class that inherits from Printable.
//
// The aim is for screen class to keep a
// reference to the Box object added it. That
// when that box increases or decreases,
// Screen classes Box will do the same.
// In CPP I wouldn't need the Box wrapper class
// and would just use pointers to pointers.
public void
addPrintable(Jav.util.Box<Printable> p)
{
// pushBack was declared in Jav.util.Iterator
p2.pushBack(p);
}
}
Main.java
package main; // easier to make jar file
import ConsoleGraphics.*;
import Jav.util.*;
public class Main
{
public static void main(String[] args)
{
Box<StringPrintable> nums = new Box<>();
Screen sodoku_game = new Screen();
// error no matching function!
sudoku_game.addPrintable(nums);
}
// Now imagine if someone inherits
class TransformableChars extends Printable
{
/** extends code with techniques to make
Printable Transformable */
}
}
答案 0 :(得分:1)
无论vector<x>
和vector<y>
是什么类型,两种类型x
和y
都不是“兼容的”。容器始终是不同的类型。这就是C ++中的规则。
在您使用class B : A {};
的示例中,派生类从基类继承私有。因此,它们之间的联系甚至是一个秘密。
class B : public A {};
的情况有所不同,现在每个人都可以使用每个B
还包含A
部分的事实。
那仍然不允许您互相分配不同的向量类型,但是可以允许分别分配每个元素。 B
对象也是A
。
向量类为此具有成员函数,因此您可以这样做
a.assign(b.begin(), b.end());
这将复制每个A
的{{1}}部分,并将该副本存储在B
-向量中。
它仍然会导致object slicing,并且不会将a
变成vector<a>
,但是确实会将每个vector<b>
中的值(部分)分配给{ {1}}。这种切片是否可以接受当然取决于应用程序。
答案 1 :(得分:1)
={query(Data1!A4:B,"select * where A is not NULL label A '"&Data1!B1&"'");query(Data2!A4:B,"select * where A is not NULL label A '"&Data2!B1&"'");query(Data3!A4:B,"where A is not NULL label A '"&Data3!B1&"'")}
在其元素类型上是不变,这意味着,即使向量之间的关系相关,不同向量之间也没有关系(从继承意义上来说)。有关类型差异的更多信息,请参见this article。
答案 2 :(得分:0)
我在这里可以看到两个问题。
首先,您试图分配(在本例中为副本)向量,即使它们只是已声明但尚未初始化。现在,这并不总是造成问题(例如,向量初始化为空),但是最好不要使用它,因为这样可以得到许多未定义的行为。
第二个是,即使B
是A
的派生类,它们仍然是不同的类。
这样,保存a
类对象的向量A
无法复制保存b
类型的类对象的向量B
。它们是完全不同的向量。如果您查看std::vector
的副本构造函数的文档,就可以看到以下内容:
@param __x A %vector of identical element and allocator types.
请注意,如果您创建两个A
的子类,它们的名称除了名称之外在其他方面都相同,那么甚至会发生这种情况。
要解决此问题,您可以创建一个在初始化重要数据时为您执行复制的功能,如下所示:
void copyAtoB(const A& a, B& b) {
b.data = a.data;
}
不过,要执行此操作,您需要将B
设为public A
。完成后,您可以创建矢量,如下所示:
std::vector<A> a = { /* some data */ };
std::vector<B> b;
for (auto& item : a) {
auto tempB = new B;
copyAtoB(item, *tempB);
b.push_back(*tempB);
}
答案 3 :(得分:0)
好的,再次感谢大家的投入,我想你们实际上帮助了我找回自己的路。 L. Kue提供的代码特别有用,即使它需要更通用。并提醒我我已经使用SFML Vector模板解决了此问题。
这是我针对CPP和Java的解决方案。
C ++
#include <vector>
struct A {};
struct B : A {};
struct C : B {};
// Modify vector to do the conversions
template <class T>
struct Vector : std::vector<T>
{
Vector();
Vector(std::size_t size);
Vector(const Vector ©);
template <class E>
Vector(const Vector<E> ©);
// Everything seem to work fine without
// assignment operators but I wrote them in case.
Vector& operator= (const Vector ©);
template <class E>
Vector& operator= (const Vector ©);
};
template <class T>
Vector<T>::Vector() : std::vector() {};
template <class T>
Vector<T>::Vector(std::size_t size)
: std::vector<T>(size) {};
template<class T>
Vector<T>::Vector(const Vector ©)
: std::vector<T>(copy) {};
template <class T>
template <class E>
Vector<T>::Vector(const Vector<E> ©)
: std::vector<T>( copy.size() )
{
static_assert(std::is_base_of<T,E>::value,
"Error : Rvalue is not base of Lvalue");
auto copy_iter = copy.begin();
for (auto & iter : *this)
{
iter = *copy_iter; ++copy_iter;
}
}
template <class T>
Vector& Vector<T>operator= (
const Vector ©)
{
std::vector<T>::operator=(copy);
}
template <class T>
template <class E>
Vector& Vector<T>::operator= (
const Vector ©)
{
static_assert(std::is_base_of<T,E>::value,
"Error : Rvalue is not base of Lvalue");
auto copy_iter = copy.begin();
for (auto & iter : *this)
{
iter = *copy_iter; ++copy_iter;
}
}
int main()
{
Vector<A> a(100);
Vector<B> b(50);
Vector<C> c(100);
Vector<A> a1 = b;
a = b;
a = c;
b = c;
b=a; // static assertion fails! Great!
}
Java
我必须做一些研究,因为Java泛型与C ++模板非常不同。我从www.mindview.net学到了很多东西。
class A {};
class B extends A {};
class C extends B {};
class Box<T>
{
@SuppressWarnings("unchecked")
public Box() { obj = (T[]) new Object[0]; }
@SuppressWarnings("unchecked")
public Box(int size, T elem)
{
obj = (T[]) new Object[size];
for(int i=0; i<obj.length; ++i) obj[i] = elem;
}
// Trying to achieve the same with a template
// E and template T will not work.
@SuppressWarnings("unchecked")
public Box(Box<? extends T> copy)
{
obj = (T[]) new Object[copy.length];
for(int i=0; i<obj.length; ++i)
obj[i] = copy.obj[I];
}
@SuppressWarnings("unchecked")
public void pushBack(T elem)
{
// Not efficient way of adding elements
T[] temp = obj;
obj = (T[]) new Object[obj.length + 1];
for(int i=0; i<obj.length-1; ++i)
obj[i] = temp[i];
final last_index = obj.length-1;
obj[last_index] = elem;
}
public T get(int index) { return obj[index]; }
public void clear() { obj = null; }
public Object array() { return obj; }
private T obj[];
}
public class Main
{
static void foo(Box<A> a)
{
System.out.println("mission accomplished!");
}
public static void main(String[] args)
{
Box<B> b = new Box<>();
Box<C> c = new Box<>();
Box<A> a = new Box<>(b);
Box<A> a1 = new Box<>(a);
a = new Box<>(c);
b = new Box<>(c);
foo(a);
foo(a1);
foo( new Box<>(b) );
foo( new Box<>(c) );
b = new Box<>(a); // unresolved compiler error
c = new Box<>(a); // unresolved compiler error
c = new Box<>(b); // unresolved compiler error
a = b; // compiler error from day 1
// can't change!
}