在多态类中重载赋值运算符

时间:2013-09-14 01:04:19

标签: c++ polymorphism operator-overloading assignment-operator

我来自java,所以请耐心等待。我已经阅读了其他几篇文章,似乎无法找到答案。

我有一个基类(Obj)头文件如下所示。

class Obj {
public:
    Obj();
    Obj(int);
    int testInt;
    virtual bool worked();

    Obj & operator = (const Obj & other) {
        if(this != &other) {
            //other.testInt = this->testInt;
            return *this;
        }
    }
};

基础课程

Obj::Obj() {

}

Obj::Obj(int test) {
    this->testInt = test;
}

bool Obj::worked() {
    return false;
}

这是子类标题

class Obj1 : public Obj {
public:
    Obj1();
    Obj1(int);
    virtual bool worked();
};

儿童班

#include "Obj1.h"

Obj1::Obj1() {

}

Obj1::Obj1(int a) {
    this->testInt = a / 2;
}

bool Obj1::worked() {
    return true;
}

这是我的主要课程

int main() {
    Obj obj = Obj(99);
    Obj1 obj1 = Obj1(45);

    obj = obj1;

    if(obj.worked())
        cout << "good" << obj.testInt << endl;
    else cout << "bad " << obj.testInt  << endl;

    if(obj1.worked()) {
        cout << "1good " << obj1.testInt << endl;
    } else
        cout << "1bad " << obj1.testInt << endl;
    return 0;
}

这是运行时的输出

bad 99
1good 22

我如何得到它 obj = obj1; (在上面的主要部分中找到)使得obj.worked()将返回true(因为这是obj1的类如何定义它)?基本上我如何让它像在java中一样?我不需要深层复制,我只想抛弃obj用于引用的内容并将其指向obj1(我认为这是如何在java中工作的。)

2 个答案:

答案 0 :(得分:1)

注意:我对Java不是很熟悉。

C ++和Java中的“变量”之间存在重大差异:

class X { public: int m = 5; };

X a; // no `= X();` required
X b;

a = b;
a.m = 42;
print(b.m); // this line is pseudo-code

在Java中,变量可能指向不同的对象。在上面的示例中,在分配后,ab指向同一个对象。通过一个修改此对象将使修改在通过另一个对象访问对象时可见,print(b.m)将打印42

在C ++中,“变量”(实际上:名称)总是引用同一个对象。有两个对象,一个名为a,另一个名为b,分配不会改变它。根据默认/约定,C ++中的赋值意味着(深层)复制。 a = b将由大多数人解释,在内置类型的情况下,b的内容复制到a (或者,更正式地,< em>更改a,以便之后等于b,而不会更改b

现在应该很清楚,你不能通过在C ++中使用赋值来改变调用worked的覆盖:根据对象的类型选择调用虚函数的覆盖(动态类型) ),并且您无法更改名称(变量)引用的对象。


但是,C ++中有一些指针,即所谓的原始指针智能指针。指针是指向一种特定类型的其他对象的对象本身。 X*是一个原始指针,指向类型为X 的对象,即使具有多态性!同样,std::shared_ptr<X>是一个指向类型对象的智能指针X

std::shared_ptr<X> pa = std::make_shared<X>();
std::shared_ptr<X> pb = std::make_shared<X>();

每个make_shared都会创建一个对象。因此,我们在此示例中有四个对象:papb和通过make_shared创建的两个未命名对象。

对于指针,有几个运算符用于处理指向的对象。最重要的是星号,取消引用指针。 *pa将为您提供pa个对象。 pa->运算符是(*pa).的简写,因此您可以使用它来访问指向的对象的成员。 指针的赋值不会复制指向的对象。在分配pa = pb之后,两者都将指向同一对象。对于智能指针,这意味着清理不再引用的对象:

std::shared_ptr<X> pa = std::make_shared<X>();
std::shared_ptr<X> pb = std::make_shared<X>();
// 4 objects exist at this point
pa = pb;
// only 3 objects still exist, the one `pa` formerly pointed to was destroyed

C ++中的多态性现在可以使用引用(此处未解释)或指针。我之前说过,指针只能指向一种特定类型的对象。关键是这个物体可能是更大物体的一部分,例如通过作文。但是C ++中的继承与组合非常相似:基类的所有成员都成为派生类对象的基类子对象的一部分:

std::shared_ptr<Obj1> pobj1 = std::make_shared<Obj1>();
std::shared_ptr<Obj> pobj = pobj1;

此处,pobj指向对象Obj内的 *pobj1基类子对象(即在对象pobj1内指向)。

多态现在可以通过虚函数运行。那些具有实际调用函数的特殊规则。表达式*pobj为我们提供了pobj指向的对象,它的类型为Obj。但是在这个例子中,它只是一个基类子对象,即我们最初创建的对象是从Obj派生的类型。对于这些情况,我们区分表达式的 static 动态类型

  • *pobj的静态类型始终为Obj - 对于对象p,其类型为指向some_type 的指针,静态类型*p只是some_type,删除了一个间接级别/一个指向的指针。
  • 动态类型*pobj取决于当前指向的对象pobj,因此通常在编译时不知道。如果对象是基类子对象,我们使用它所属的派生类对象,并递归直到我们拥有的对象不是基类子对象了。我们最终得到的对象的类型是表达式的动态类型。在上面的示例中,pobj指向Obj *pobj1基类子对象。对象*pobj1本身不是基类子对象,因此*pobj的动态类型为Obj1

此动态类型现在用于选择调用哪个虚函数重写。如果pobj->worked()的动态类型*pobjObj1,则所选择的覆盖为Obj1::worked,将返回true。

N.B。正如Ben Voigt指出的那样,动态类型不依赖于构成。它只是关于继承。

答案 1 :(得分:-1)

在C ++中,您的对象是值,而不是java中的引用。赋值(obj = obj1)将引用Obj1的Obj部分。在C ++中,您必须使用指针或引用。

  • 指针

    Obj* obj = new Obj(99);
    Obj1* obj1 = new Obj1(45);
    delete obj;// you have to free the memory manually as there's no GC in C++
    obj = obj1;
    obj->Worked();// the worked will be true here
    delete obj1; // manually delete it
    

    如果你想通过obj删除obj1(删除obj而不是删除obj1),你必须将Obj的析构函数更改为虚拟,否则不会调用Obj1的析构函数。该死的,这是C ++,喜欢它。

  • 参考

    Obj obj = Obj(99);
    Obj1 obj1 = Obj1(45);
    Obj& obj2 = obj1;
    obj2.Worked() // should be true    
    

    在这种情况下,与指针不同,您不必删除堆栈上的对象(不是由“new”创建的)。但是你不能创建一个Obj&amp;数组。 (例如矢量)