【问题标题】:Usage of virtual class and extern in C++C++中虚类和extern的使用
【发布时间】:2010-11-15 22:52:09
【问题描述】:

当我还是学生的时候,我一直在使用 C++ 进行开发,但我从未在任何项目中使用 C++ 中的虚拟类或 extern。我最近刚读到这两个,希望有人对它们的用法有更好的了解。

虚拟类的目的是什么?可以使用/实现它的示例。我在 IBM 网站上稍作修饰,并编写了一个测试程序来查看它的运行情况,但是什么时候使用虚拟类比较好?

extern 也是如此。我看到了一个例子,并在C++中为自己做了一个测试,但是使用extern而不是使用头文件有什么好处?头文件代替extern有什么好处?

【问题讨论】:

  • 你的意思是一个使用虚拟继承的类吗?还是抽象基类?
  • 我试图了解什么时候可以使用它。这是我从 IBM 网站获得的示例:publib.boulder.ibm.com/infocenter/comphelp/v8v101/…
  • 好的,根据您提供的链接,您正在询问使用虚拟继承的类。

标签: c++ class virtual extern


【解决方案1】:

虚拟课程适用于您遇到dreaded diamond。例如:

struct Base { int x; };
struct D1 : Base {};
struct D2 : Base {};
struct Derived : D1, D2 {};

这里,Derived 实际上有 两个 Base 部分,因此 两个 成员变量称为 x。它会编译,但在通过其基类之一操作 Derived 对象时,您可能会遇到一些意外行为。

Derived derived;
D1& d1 = derived;
D2& d2 = derived;
d1.x = 1;
d2.x = 2;
cout << d1.x << d2.x << endl; // 12 !

虚拟继承通过使Derived 仅从Base 派生一次来解决此问题。

struct Base { int x; };
struct D1 : virtual Base {};
struct D2 : virtual Base {};
struct Derived : D1, D2 {};

这里,Derived 只有一个Base 部分和一个名为x 的成员变量。

【讨论】:

  • 哇!如果我们在学校报道过,我就完全忘记了。我记得的是笼统的“不要使用多重继承”语句。 +1,我今天学到了一些新东西,并且以清晰简洁的方式:-)
  • 很好的例子。我在学校也被教过,“不要使用多重继承”,并且由于很多课程都是基于 Java 的,因此几乎受到了限制。感谢您解决这个问题。
  • 至于“不要使用多重继承”——在很多情况下我仍然会坚持这个建议。虚拟继承令人困惑,它只会吓唬人。尽量只在只有一个类有成员变量时才使用多重继承(其余都是空接口)。
【解决方案2】:

虚拟继承

没有虚拟类,但有虚拟继承,虚拟继承的基类通常称为虚拟基类。

例子:

#include <iostream>

class IHello
{
public:
    virtual char const* message() const = 0;
};

class HelloImpl
    : public virtual IHello     // Use virtual inheritance for interface
{
public:
    virtual char const* message() const { return "Hello"; }
};

class Abstract
    : public virtual IHello     // Use virtual inheritance for interface
{
public:
    void sayHello() const
    {
        using namespace std;
        cout << "I'm saying... " << message() << "!" << endl;
    }
};

class Concrete
    : public Abstract
    , public HelloImpl
{};

int main()
{
    Concrete().sayHello();
}

这里的虚继承有如下作用:

  • IHello类的基类子对象只有一个。

  • IHello的单个子对象直接由派生最多的类初始化,这里是Concrete

  • 对模糊访问的普通规则稍作修改,这样访问message 就可以了,而HelloImpl 类通过dominance 提供了message 的实现,有点像在 Java 和 C# 中,除了它在 C++ 中更通用。

如果你把虚拟继承换成普通继承,那么上面的代码连编译都不会。

extern 与头文件

extern 和头文件是正交的概念。

extern 表示某事物具有外部链接,extern 是语言的一部分,是一个关键字。

头文件是一种打包代码的方式。通常将声明放在头文件中,以便可以通过#include 预处理器指令引入这些声明。头文件不是语言的一部分(尽管预处理器是)。

因此,“使用extern 代替头文件”是没有意义的。

没有特定的关系,也没有可以用一个代替另一个的任务。

干杯,

【讨论】:

    【解决方案3】:

    Virtual Class 用于消除菱形问题。为了更好地理解这个问题,考虑一下场景

    #include <iostream>
    using namespace std;
    class A
    {
    
    public:
        int i;
    
    
    };
    class B:public A
    {
    
    public:
    
        int j;
    };
    class C:public A
    {
    
    public:
    
        int k;
    };
    
    class D:public B,public C
    {
    public:
        int l;
    
    };
    
    
                A
               / \
              /   \
             B    C
             \    /
              \  /
                D
    

    这里 B 和 C 继承了 A。所以属性(变量和函数)都存在于两个类中。同样,当 D 继承 C 和 B 时,B 和 C 的属性以及存在于两个类中的 A 的属性都存在于类 D 中。因此出现了矛盾。这个问题是菱形问题。 这可以删除我将基类 A 作为防止这种重复的虚拟类。 谢谢

    【讨论】:

      猜你喜欢
      • 2019-12-22
      • 2016-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-21
      • 2021-07-15
      相关资源
      最近更新 更多