当前位置:  编程技术>c/c++/嵌入式
本页文章导读:
    ▪钻石继承与虚继承      首先,何为钻石继承,顾名思义,在类的继承过程中,继承结构是一个类似菱形(钻石)的结构就属于钻石继承,如下:               &nb.........
    ▪C++ primer 学习笔记(2):函数      1:下列情况采用引用形参:需要在函数中修改实参的值;需要以大型对象作为实参传递,没法实现对象的复制。2.使用引用形参还可以额外的信息。3.应该将不需要修改的引用形参定义为const.........
    ▪将LINUX默认启动级别修改为字符界面             这一行,修改成  id:3:initdefault:       输入startx 命令起动图形界面。 Issay Tseng 2013-01-05 12:44 发表评论......

[1]钻石继承与虚继承
    来源:    发布时间: 2013-10-14

首先,何为钻石继承,顾名思义,在类的继承过程中,继承结构是一个类似菱形(钻石)的结构就属于钻石继承,如下:

                                                     

这是一个最简单的钻石继承。实际上,在复杂的继承表中,只要子类按不同的继承路径回溯到基类有菱形结构,均属钻石继承。下面先看一个例子,钻石继承在C++程序设计中带来的问题。

1 //diamond.cpp
2 #include<iostream>
3 using namespace std;
4 class A{
5 public:
6 A (int x) : m_x(x) {}
7 int m_x;
8 };
9 class B : public A {
10 public:
11 B (int x) : A(x) {}
12 void set(int x) {
13 this -> m_x = x;
14 }
15 };
16 class C : public A {
17 public:
18 C (int x) : A(x) {}
19 int get(void) {
20 return this -> m_x;
21 }
22 };
23 class D : public B,public C {
24 public:
25 D (int x) : B(x),C(x) {}
26 };
27 int main(void) {
28 D d(10);
29 d.set(20);
30 cout << d.get() << endl;
31 return 0;
32 }
33

这样的运行结果是10?还是20呢?结果是10,为什么?!明明sets的是20,为什么get的还是10呢?

要解释这个问题那酒必须要先搞清楚,d对象在内存中是如何存放的,是怎样布局的。每一个子类都会有一个内存视图,在子类里都包含了它的基类子对象,下面是创建是d对象时,d对象在内存中的存放形式。

包含一个B类的基类子对象和一个C类型基类子对象,而B和C里各自有一个A类型基类子对象,所以可以看到,在d的内存布局中有两个A类型基类子对象。

set函数是类B的成员函数,在执行set函数时,this指针指向B(其实也是指向A,B从A继承,A存在B中的首地址),所以set执行后,改变的是B里的A类基类子对象的数据成员的值。同理,get函数得到的是C里A类基类子对象的数据成员的值。这样就可以理解这样的运行结果了。所谓钻石继承问题,就是公共基类对象在我们最终的子类对象中有多个副本,多份拷贝,当我们沿着不同的继承路径去访问公共基类子对象时结果会出现不一致。

而我们应该怎样解决这样的问题呢?采用虚继承。我们所期望的d的存储形式:

我们需要按如下方式修改代码:

class B : virtual public A //虚继承

class C : virtual public A //虚继承

D(int x) : B(x),C(x),A(x) {}

这样就解决了。

在这个过程中,A对象只在D的初始化表中A(x)进行构造(虚基类最先被构造),而在B和C的初始化表中不再对A进行构造(实际上是都有一个指针指向了D中的A(x),来对A进行构造)。

钻石继承,在访问公共基类成员函数时,如果不是虚继承,还会引起二义性的错误。代码如下:

1 //diamond.cpp
2 #include<iostream>
3 using namespace std;
4 class A{
5 public:
6 A (int x) : m_x(x) {}
7 void foo() {
8 cout << "A::foo()" << endl;
9 }
10 int m_x;
11 };
12 class B : public A {
13 public:

    
[2]C++ primer 学习笔记(2):函数
    来源:    发布时间: 2013-10-14

1:下列情况采用引用形参:需要在函数中修改实参的值;需要以大型对象作为实参传递,没法实现对象的复制。

2.使用引用形参还可以额外的信息。

3.应该将不需要修改的引用形参定义为const引用。因为非const引用形参既不能用const对象初始化,也不能用字面值或产生右值的表达式初始化。(左值右值傻傻分不清楚,找到一篇文章左值右值)

4.函数可以为形参定义默认实参,但如果有一个形参定义了默认实参,则他后面的所有形参都必须定义默认实参。在一个文件中,只能为一个形参指定默认实参一次。

5.内联机制适用于优化小的,只有几行的而且经常被调用的函数。内联函数应该在头文件中定义。

本文链接


    
[3]将LINUX默认启动级别修改为字符界面
    来源:    发布时间: 2013-10-14
   
  用文本编辑器修改 /etc/inittab文件 ,把
  代码:
  
  id:5:initdefault: 
  
  这一行,修改成
  代码:

  id:3:initdefault: 

      输入startx 命令起动图形界面。 






Issay Tseng 2013-01-05 12:44 发表评论

    
最新技术文章:
▪C++单例模式应用实例
▪C++设计模式之迭代器模式
▪C++实现动态分配const对象实例
▪C++设计模式之中介者模式
▪C++设计模式之备忘录模式
▪C++插入排序算法实例
▪C++冒泡排序算法实例
▪C++选择排序算法实例
▪C++归并排序算法实例
▪C++设计模式之观察者模式
▪C++中复制构造函数和重载赋值操作符总结
▪C++设计模式之状态模式
▪C++ COM编程之什么是接口? iis7站长之家
▪C++设计模式之访问者模式
▪C++设计模式之模板方法模式
▪C++实现下载的代码
▪C++模板之特化与偏特化详解
▪C++实现查壳程序代码实例
▪C语言、C++内存对齐问题详解
▪C语言、C++中的union用法总结
▪C++基于CreateToolhelp32Snapshot获取系统进程实例
▪C++中memcpy和memmove的区别总结
▪C++通过TerminateProess结束进程实例
▪C++内存查找实例
▪C++实现CreatThread函数主线程与工作线程交互的...
▪C++设计模式之桥接模式
▪C++中关键字Struct和Class的区别
▪C++设计模式之组合模式
▪C++ COM编程之什么是组件?
▪C++ COM编程之什么是接口?
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3