0

我来自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; (在上面的 main 中找到)使得 obj.worked() 将返回 true(因为这就是 obj1 的类定义它的方式)?基本上我如何让它表现得像在java中一样?我不需要深拷贝,我只想扔掉 obj 曾经引用的内容并让它指向 obj1(我认为这就是它在 java 中的工作方式)。

4

2 回答 2

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++ 中,“变量”(实际上是:名称)总是指同一个对象。有两个对象,一个是 named a,一个是 named b,赋值不会改变它。根据默认/约定,C++ 中的赋值意味着(深度)复制。a = b将被大多数人解释为,在内置类型的情况下,复制btoa的内容(或者更正式地说,更改a为之后等于b,而不更改b)。

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


但是,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创建一个对象。所以在这个例子中我们有四个对象:pa, pb,以及通过 . 创建的两个未命名对象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*pobj1pobj1

多态性现在通过虚函数工作。那些对实际调用哪个函数有一个特殊的规则。该表达式为我们提供了指向*pobj的对象,它的类型为。但在这个例子中,它只是一个基类子对象,即我们最初创建的对象是一个派生自的类型。对于这些情况,我们区分表达式的静态动态类型:pobjObjObj

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

这种动态类型现在用于选择调用哪个虚函数覆盖。pobj->worked()在动态类型为*pobj的情况下,Obj1选择的覆盖为Obj1::worked,这将返回 true。

NB 正如Ben Voigt所指出的,动态类型不依赖于构图。它只是关于继承。

于 2013-09-14T01:55:35.903 回答
-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的析构函数改为virtual,否则不会调用Obj1的析构函数。该死的,这是C++,享受吧。

  • 参考

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

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

于 2013-09-14T01:35:49.170 回答