如何让派生类的对象“引用”基类实例的成员?

时间:2013-08-17 01:04:36

标签: c++ oop inheritance

假设我有一个类Foo,其实现涉及一个大对象。我想扩展Foo的功能,因此我决定编写一个继承Bar的类Foo

class Foo {
protected:
    int bigobject;
public:
    Foo() : bigobject(1) { }
    int get() { return bigobject; }
    void set(int x) { bigobject = x; }
};


class Bar : public Foo {
public:
    Bar(Foo& f) { /* ??? */ }
    void multiply(int factor) { bigobject *= factor; }
};

如您所见,我将构造函数留空了。这是因为我想要做的是让任何Bar对象的基本成员都引用现有Foo实例的成员。换句话说,我想要代码:

Foo f;
f.set(5);
std::cout << "f is " << f.get() << std::endl;

Bar b(f);
std::cout << "b is " << b.get() << std::endl;
b.multiply(2);
std::cout << "b is " << b.get() << std::endl;
std::cout << "f is " << f.get() << std::endl;

导致:

f is 5
b is 5
b is 10
f is 10

因此fb的基本部分共享相同的内存空间。这是为了避免在我想要实例化bigobject的任何时候复制Bar。在非正式的术语中,我希望Bar对象b成为Foo对象f的“视图”。调用任何Foo成员方法都会更改f,但我也可以在Bar中定义更多方法,这些方法也会更改f

现在,我可以声明一个全局“存储”变量:

int bigobject_storage = 1;

class Foo {
protected:
    int& bigobject;
public:
    Foo() : bigobject(bigobject_storage) { }
    int get() { return bigobject; }
    void set(int x) { bigobject = x; }
};

class Bar : public Foo {
public:
    void multiply(int factor) { bigobject *= factor; }
};

要获得我想要的功能,但这似乎是hackish并且漏掉了实现。那么,有没有一种惯用的C ++方法来实现这个目标呢?

2 个答案:

答案 0 :(得分:1)

David Wheeler似乎对报价负责

  

计算机科学中的所有问题都可以通过另一层次的间接来解决。

这适用于您的情况:让您的基类Foo存储指向相关大对象的[智能]指针,并在相关实例之间共享相应的指针。当默认构造Foo对象时,会分配并指向一个大对象。复制Foo个对象时,新的Foo对象设置为引用与原始对象相同的大对象。但请注意,这意味着Foo基数的行为更像是对值的引用。

实际上,你可能会使用这样的东西:

class Foo {
protected: // I don't really believe in protected data members! Don't use them!
    std::shared_ptr<int> bigobject;
public:
    Foo(): bigobject(new int()) {}
    Foo(Foo const& other): bigobject(other.bigobject()) {}
    // ...
 };

 Bar::Bar(Foo& other): Foo(other) { /*...*/ }

答案 1 :(得分:0)

只需使用OOP概念即可实现您想要的效果。

您需要做的只是指向对象的指针,多态性将完成这项工作。

你没有在你的代码中改变任何东西,也不必给Bar一个Bar的副本,你需要做的就是调用基类的构造函数(虽然这是自动完成的,如果是派生类中的默认构造函数。

这样的事情:

class Foo {
protected:
    int bigobject;
public:
    Foo() : bigobject(1) { }
    int get() { return bigobject; }
    void set(int x) { bigobject = x; }
};


class Bar : public Foo {
public:
    Bar() : Foo() { }
    void multiply(int factor) { bigobject *= factor; }
};

诀窍在于决定如何“查看”对象。 因为Foo是Bar的基类,所以Bar拥有Foo所拥有的一切。换句话说,Bar是Foo加上你在Bar中定义的。因此,指向Bar的Foo指针将表现为Foo对象,即使它指向Bar。

代码如下:

Bar b();
/* 
/* f and b point to the same object.
/* But, to the compiler, f does'nt know anything of b and its methods,
/* because f is a pointer to Foo.
 */
Foo *f = &b;
f->set(5)
std::cout << "f is " << f->get() << std::endl;

std::cout << "b is " << b.get() << std::endl;
b.multiply(2);
std::cout << "b is " << b.get() << std::endl;
std::cout << "f is " << f->get() << std::endl;

要获得此结果:

f is 5
b is 5
b is 10
f is 10

即使您正在保存一个对象的内存,因为您使用的是同一个对象,但被视为不同的类。那就是多态性。