hellohuan

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  2 Posts :: 3 Stories :: 0 Comments :: 0 Trackbacks

常用链接

留言簿(1)

我参与的团队

搜索

  •  

最新评论

阅读排行榜

评论排行榜

 

Fucking in c++第十三章笔记

 

1、组合就是由类成员(或称成员类)组成新类

2、继承实际上也是由基类做子成组成新类,但语法上有不同,体现了OOP的思想

基类在继承类中默认是私有的,以Y:public X形式继承则变为公有。

从继承类的外部调用基类的任何成员都要加上基类名,如Y y; y.X::f( ); 而对于成员类则要加上对象名y.x.f( );

3   由于C++强制初始化,因此基类和成员类都必须在新类的构造函数初始化列表中初始化

初始化语法:对于基类,使用类名调用构造函数;对于成员类,使用对象名调用构造函数,如Y::Y(int i):X(i), x(i) {}

4    继承类默认继承了基类的成员函数,即,在不重定义的前提下,y.f( )y.X::f( )调用的同一个函数

而组合类则必须通过成员类对象进行函数调用

继承类和组合类的构/析造函数调用次序相反,前者从基类到子类

5   如果重定义了基类的函数,则基类的同名函数全部自动隐藏。

所谓“全部”是因为,可能在基类中有多个同名的重载函数,它们全部隐藏

所谓“隐藏”不是说不能调用,而是说,当调用y.f( )时调用的是Y中定义的新f( ),想调用基类的f则要显式说明y.X::f( )

6   所有构造函数、析构函数、operator=都不能自动继承

但编译器会自动生成默认构造函数、拷贝构造函数、operator=,并正确地调用基类的相应函数,它们工作的很好

自动类型转换函数会自动继承

    如果想让编译器自动创建子类的默认构造函数,我们就不能为子类定义任何(包括拷贝)构造函数。这和普通类的规则是一样的

但是如果不为子类定义任何构造函数,则只能使用自动生成的默认和拷贝构造函数

因此,如果想为子类定义带参数的构造函数,则必须同时也定义子类的默认构造函数

如果自定义了拷贝构造函数,则也必须同时自定义默认构造函数

在子类的默认构造函数中,如果想调用基类的默认构造函数,无需显式调用

在子类的拷贝构造函数中,如果想调用基类的拷贝构造函数,必须显式在初始化列表调用,否则自动调用默认构造函数

在子类的operator=中,如果想调用基类的operator=必须显式在函数体中调用,否则编译器什么也不做

8   静态成员函数的继承规则和非静态成员函数一样,只是static成员函数不能是virtual

9    所以最好的方案是:

如果不定义带参数的构造函数,就什么都不要动,编译器自动生成符合要求的默认/拷贝构造、析构、operator=

如果必须定义带参构造函数,就要同时定义默认构造函数,但定义时无需显式调用基类默认构造函数

没事就不要自定义拷贝构造函数和operator=,如果一定要重定义,必须显式调用基类的拷贝构造函数和operator=

10   可以看到,组合类和继承类的编译器实现是一样的

到目前为止,两者区别在于继承类继承了基类的函数接口,继承是is-a关系,组合是has-a关系

C++默认是私有继承,即此时并不能直接通过子类对象调用基类函数(即y.X::f()),而要在Y内用using X::f;

11   protected的意义是仅自己和子类可以访问自己的成员,外部不可访问

private-protected-public的关系很像linux中文件权限的owner-group-others的关系

也可以protected继承,但通常没有应用实例,它的存在只为语言的完备性 

12 operator=之外的所有基类运算符都会自动继承,但它们操作的都是子类中“基类的成员”

,即,如果XY都有int成员i,则Y y;++y;加的是X中的i,而不是y中的i;同理operator==的意义也不会检测y中的i

13   C++支持多重继承,但作者认为多重继承总可以转化为单重继承,并且多重继承很难掌握,因此不建议使用。

14   继承和组合的优点之一是支持渐进式开发。程序员应当更多关心处理数据关系,而不是进行具体的位操作

15   子类可以自动向上类型转换为基类,这对于类本身、类指针、类引用都有效

在编译器自动生成的子类拷贝构造函数中,首先执行基类拷贝构造函数,之后按声明顺序执行成员类拷贝构造函数

多重继承可以通过组合类的形式代替

指针和引用被自动向上类型转换之后,子类的成员会不能访问,这将通过下一章的virtual函数解决

////////////////////////////////////////

#include <iostream>
using namespace std;

class A {
    
int i;
public:
    A( 
int I ) { i = I; 
    cout
<<"a is fucking"<<endl;}

    
~A() {cout<<"a is not fucking"<<endl;}
    
void f() const {}
}
;
class B {
    
int i;
public:
    B( 
int I ) { i = I;cout<<"b is fucking"<<endl; }
    
~B() {cout<<"b is not fucking"<<endl;}
    
void f() const {}
}
;
class C : public B {
    A a;
public:
    C( 
int I ) :  a( I ),B( I ) {cout<<"c is fucking"<<endl;}//调用了基类的构造函数和成员对象的构造函数
    ~C() {cout<<"c is not fucking"<<endl;}//调用~A与~B
    void f() const {//重定义了所继承的B::f(),并且还调用基类的版本。(只能在继承期间重定义函数)
        a.f();//通过成员对象,只能操作这个对象的公共接口,而不能重定义它
        B::f();//
    }

}
;


int main()
{
    C c(
3);
    
return 0;
}
结果:
b is fucking
a is fucking
c is fucking
c is not fucking
a is not fucking
b is not fucking

先初始化基类,随后构造组合类,之后才是子类,析构顺序正好相反,恰好回答了上次做错的笔试题
posted on 2008-07-29 22:10 炮灰九段 阅读(161) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理