c++ primer 面向对象编程笔记
来源:互联网 发布:唐山直销软件 编辑:程序博客网 时间:2024/05/01 04:22
在C++中,通过基类的引用(或指针)调用虚函数时,发生动态绑定。引用(或指针)既可以指向基类对象也可以指向派生类对象。
(2) 虚函数
1) 保留字virtual只在类内部的成员函数声明中出现,不能用在类定义体外部初相的函数定义上。
2) 派生类中虚函数的声明必须与基类中的定义完全匹配,但有一个例外:返回对基类型的引用(或指针)的虚函数。派生类中的虚函数可以返回基类函数类型的派生类的引用(或指针)。
1
2
3
4
5
6
7
8
class Base
{
virtual Base &f();
};
class Derive: public Base
{
Derive &f();
};
3) 默认实参
1、 通过基类的引用或指针调用虚函数时,默认实参是基类声明中的值;
2、 通过派生类的指针或引用调用虚函数时,则默认实参是派生类声明中的值;
这里就会产生一种情况,通过基类的引用或指针调用,而实际上执行的是派生类中定义的版本,而默认实参确实基类定义的参数。
01
02
03
04
05
06
07
08
09
10
11
12
class Base
{
public:
virtual void f(int x = 1);
};
class Derive: public Base
{
public:
void f(int x = 2);
};
Base *pBase = new Derive;
pBase->f(); //默认实参x=1,调用Derive::f()
(3) protected成员
1) 像private成员一样,protected成员不能被类的用户访问;
2) 像public成员一样,protected成员可被该类的派生类访问;
01
02
03
04
05
06
07
08
09
10
11
12
13
class Base
{
protected:
int x;
};
class Derive: public Base
{
void f(Derive &d, Base &b)
{
d.x = 1;
// b.x = 1; //error
}
};
(4) 作用域
在继承情况下,派生类的作用域嵌套在基类作用域中。在基类和派生类中使用同一名字的成员函数,在派生类作用域中派生类成员将屏蔽基类成员,即使函数原型不同。
01
02
03
04
05
06
07
08
09
10
11
12
class Base
{
public:
void f();
};
class Derive: public Base
{
public:
void f(int x);
};
Derive *d;
//d->f(); //error
解决的方法有两种,第一种是显示使用作用域操作符,第二种使用using声明获得重载函数的行为。一个using声明只能指定一个名字,不能指定形参表。有一种特殊情况,如果using声明的函数原型在派生类中已有定义,则派生类中的函数依然会屏蔽基类中的函数。
01
02
03
04
05
06
07
08
09
10
11
12
//方法一:显示使用作用域
d->Base::f();
//方法二:使用using声明
class Derive: public Base
{
public:
using Base::f;
//...
};
Derive *d = new Derive;
d->f();
using声明的另一种作用是改变继承成员的访问级别,但不能使访问级别比基类中原来指定的更宽松。
01
02
03
04
05
06
07
08
09
10
class Base
{
public:
void f();
};
class Derive: private Base
{
public:
using Base::f; //这里的f函数恢复为public
};
对于虚函数,有两个原则:1、只有成员函数中的代码才应该使用作用域操作符覆盖虚函数机制;2、派生类虚函数调用基类版本时,只能显式使用作用域操作符。
(5) 派生类到基类转化的可访问性
要确定到基类的转换是否可访问,可以考虑基类的public成员是否可访问,如果可以,转换是可访问的,否则转换是不可访问的。
这里可以这样理解,如果在派生类中不能访问基类的public成员,则说明派生类中不能访问基类的任何成员(派生类中对基类那部分完全不可见且不可操作),所以在该派生类中任何出现基类类型的成员函数(输入形参或返回类型)、成员变量都是错误,这里包括了从该派生类到基类的转换函数,所以不存在这样的转化函数(无论是默认或自己定义),也即不可访问的。
01
02
03
04
05
06
07
08
09
10
11
class A {};
class AA: private A {};
class AAA: public AA
{
::A m; //ok
// A m; //error
// void f(const A &); //error
};
AAA aaa;
//A a = aaa; //error
(6) 构造函数和复制控制
1) 派生类构造函数不能初始化基类的成员且不应该对基类成员赋值,这样做会违反基类的接口,派生类应通过使用基类构造函数尊重基类的初始化意图。
2) 如果派生类定义了自己的复制构造函数,该复制构造函数一般应显式使用基类复制构造函数初始化对象的基类部分。
3) 如果派生类定义了自己的赋值操作符,则该操作符必须对基类部分显式赋值。
4) 即使析构函数没有工作做,继承层次的根类也应该定义一个虚析构函数。
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
class A
{
public:
A &operator=(const A &m);
virtual ~A() {} //虚析构函数
};
class AA: public A
{
public:
AA(AA &m): A(m) //复制构造
{
//...
}
AA &operator=(const AA &m) //赋值操作符
{
A::operator=(m);
//或者直接对基类成员赋值
}
};
(7) 部分知识点
1) 如果需要声明一个派生类,则声明包含类名但不包含派生类列表。
2) 使用class保留字定义的派生类默认具有private继承,用struct保留字定义的类默认具有public继承。
3) 基类的友元对从该基类派生的类型没有特殊访问权限
- 《C++Primer》3.16 面向对象编程
- c++Primer,第十五章,面向对象编程
- c++primer——面向对象编程
- c++ primer 面向对象编程笔记
- C++primer阅读笔记---------------面向对象程序设计
- <C++Primer>第四版 阅读笔记 第四部分 “面向对象编程与泛型编程”
- C++Primer学习笔记第十五章(15/18)类 面向对象编程
- 面向对象编程与泛型编程---C++primer读书笔记
- [C/C++] 第15章:面向对象编程 《 C++ Primer 》
- c++primer 17,18章之面向对象编程 读书笔记
- 【足迹C++primer】51、面向对象编程概述
- c++primer——面向对象编程关键字
- C++ Primer学习笔记——$15 面向对象编程
- C++ Primer学习笔记——$15 面向对象编程
- C++ Primer 学习笔记十五 —— 面向对象编程
- C++ Primer 十五章 面向对象编程概述 要点笔记
- C++ Primer笔记(十三)面向对象编程
- 面向对象编程(OPP)基本术语 -----C++ primer笔记
- 内置线程
- .mdf .ldf什么文件及恢复数据库
- 毕业一周年,你收获什么?
- Ubuntu_11.10_安装教程
- MFC实现打开、保存文件对话框和浏览文件夹对话框,把代码直接拷贝到要响应的按钮函数下面就行了
- c++ primer 面向对象编程笔记
- StringBuffer 的一个骗子
- The Great IRQ Debate in the Linux kernel
- Hibernate的优化
- 左旋字符串
- 苹果欲开售“第三代IPad”
- ARMEABI
- TinyXML:一个优秀的C++ XML解析器
- javamail 使用gmail收发邮件