我试图用从该类派生的对象覆盖指向抽象类的指针的对象。 但是价值不会改变。 如果我使用指向非抽象类的指针执行相同操作,则一切都按预期工作。
我的猜测是编译器拒绝覆盖内存,因为它不知道在编译时写入的对象的确切大小。
有没有办法让我覆盖对象?
下面是一段代码来展示我的意思。 它使用g ++(Ubuntu / Linaro 4.8.1-10ubuntu9)和clang(3.2-7ubuntu1)进行测试。
#include <stdio.h>
class Abs {
public:
virtual const char *toString() = 0;
};
class A: public Abs {
public:
A(const char *s): st(s) {};
const char *toString() {return st;};
private:
const char *st;
};
class B: public Abs {
public:
B(const char *s): st(s) {};
const char *toString() {return st;};
private:
const char *st;
};
int main(void) {
//works:
A *a = new A("A");
printf("a: %s\n", a->toString());
//output: A
*a = *(new A("B"));
printf("a: %s\n", a->toString());
//output: B
//doesn't work:
Abs *x;
x = new A("A");
printf("x: %s\n", x->toString());
//output: A
*x = *(new A("B"));
printf("x: %s\n", x->toString());
//output: A
*x = *(new B("C"));
printf("x: %s\n", x->toString());
//output: A
Abs *y = new A("D");
*x = *y;
printf("x: %s\n", x->toString());
//output: A
return 0;
}
答案 0 :(得分:0)
与您的工作代码相当的最近可编译的可能是:
*static_cast<A*>(x) = *new A("A");
请注意,以下是未定义的行为:
*static_cast<B*>(x) = *new B("A");
这是因为派生最多的对象属于A
而非B
。这是一种更安全的方法:
if (A * p = dynamic_cast<A*>(x)) { *p = *new A("A"); }
答案 1 :(得分:0)
让我们逐步考虑发生的事情。
首先,您定义了指向A的指针,并通过堆中分配的A类对象的地址对其进行初始化
A *a = new A("A");
printf("a: %s\n", a->toString());
//output: A
然后,您为
指向的对象分配了一个新的已分配对象*a = *(new A("B"));
printf("a: %s\n", a->toString());
在这种情况下,调用复制赋值运算符为类A 隐式定义,并且数据成员st只是从一个对象复制到另一个对象。
因此printf输出字符串文字“B”。
现在你定义了指向Abs
的指针Abs *x;
并初始化
x = new A("A");
printf("x: %s\n", x->toString());
//output: A
考虑到x的静态类型是Abs 。
然后在所有这些陈述中
*x = *(new A("B"));
printf("x: %s\n", x->toString());
//output: A
*x = *(new B("C"));
printf("x: %s\n", x->toString());
//output: A
Abs *y = new A("D");
*x = *y;
printf("x: %s\n", x->toString());
//output: A
调用由编译器为类Abs 隐式定义的复制赋值运算符。 Abs类没有数据成员st。所以它没有改变,因为在所有这些情况下都会调用类Abs的复制赋值运算符,因为 x的静态类型是Abs 。
我想补充一下,即使在这个有效的陈述中
*x = *(new B("C"));
调用类Abs的复制赋值运算符。在这种情况下,在堆中分配的类型B的对象隐式转换为Abs。
类型如果你想要例如后面的陈述
*x = *(new A("B"));
printf输出“B”然后你应该写
*static_cast<A *>( x ) = *(new A("B"));
在这种情况下,将调用A类的复制赋值运算符。
您还可以在抽象类中编写虚拟副本赋值运算符。例如
class Abs {
public:
virtual const char *toString() = 0;
virtual Abs & operator =( const Abd & ) { return *this; }
};
并覆盖它,例如在A类
中class A: public Abs {
public:
A(const char *s): st(s) {};
const char *toString() {return st;};
A & operator =( const Abs &rhs ) { st = static_cast<const A &>( rhs ).st; return *this; }
private:
const char *st;
};
在这种情况下,在陈述
之后*x = *(new A("B"));
下一个语句将输出“B”
printf("x: %s\n", x->toString());
//output: B
注意:我们不考虑您的示例中的内存泄漏。我们正在考虑应用赋值运算符的效果。