- 结构体默认情况下,其成员是公有的。
- 类默认情况下,其成员是私有的。
- 一旦在类内定义了一个构造函数,不论这个函数带不带参数,类都不再提供默认的构造函数。
如果一个类没有定义任何的构造函数,那么编译器只会在以下三种情况,才会提供默认的构造函数。
1、如果类有虚拟成员函数或者虚拟继承父类(即有虚拟基类时);
2、如果类有基类的构造函数(可以是用户定义的,也可以是编译器提供的默认构造函数);
3、在类的所有非静态的对象数据成员,他们所属的类中有构造函数(可以是用户定义的,也可以是编译器提供的默认构造函数)
析构函数只能有一个,且不允许带任何参数在函数重载时,要注意函数带有默认参数的情况
父类构造函数、子类构造函数、子类析构函数、父类析构函数
class animal
{
public:
animal(int height, int weight)
{
}
}
class fish
{
public:
fish()::animal(400, 300)
{
}
}fish fh; 先调用父类带两个参数的构造函数,然后调用子类不带参数的构造函数
class point
{
public:
point()::x(0), y(0) //一种初始化的方式
private:
int x;
int y;
}
public 定义的成员可以在任何地方被访问
protected 定义的成员只能在该类及其子类中访问
private 定义的成员只能在该类自身中访问
基类中的private成员不能被派生类访问,因此,private成员不能被派生类所继承
举例说明:
class animal
{
public:
int publicMember;
protected:
int protectedMember;
private:
int privateMember;
}am;
class fish :public animal
{
}fh;
int main()
{
fh.publicMember = 1; //OK
fh.protectedMember = 1; //ERROR
fh.privateMember = 1; //ERROR
return 0;
}
class fish :private animal
{
}fh;
int main()
{
fh.publicMember = 1; //OK
return 0;
}
animal::publicMember”不可访问,因为“fish”使用“protected”从“animal”继承
总结一下:
- 继承类如果以public方式继承基类,则基类的三个PPP不变,然后子类继承基类。
- 继承类如果以protected方式继承基类,则基类的public变成protected,protected不变,然后子类继承基类。
- 继承类如果以private方式继承基类,则基类的public、protected变成private,然后子类继承基类。
- 总之,是先改变基类的三个PPP,然后才从基类继承。如果三个PPP都转换成了私有,则子类相当于什么也没有继承。因为私有只能在类内访问,不能在类外或者子类里面访问。
多重继承时,初始化是按照基类列表中的说明顺序进行初始化的。
虚函数与多态性,纯虚函数。
class animal
{
public:
void eat()
{
cout << "animal eat";
}
void sleep()
{
cout << "animal sleep";
}
virtual void breathe()
{
cout << "animal breathe";
}
};
class fish :public animal
{
public:
void breathe()
{
cout << "fish bubble";
}
}
void fn(animal pAn)
{
pAn->breathe();
}
void main()
{
animal pAn;
fish fh;
pAn = &fh;
fn(pAn);
}
基类中void breathe()加virtual 不加virtual的区别
不加virtual时,输出的是animal:
C++编译器将fh进行了类型转换,此时编译器认为pAn保存的就是animal对象的地址。调的当然是animal。
用virtual关键字声明的函数叫做虚函数。
C++的多态性用一句话概括就是:在基类的函数前加virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。
也就是说,多态性是按照对象的实际类型来运行的。
纯虚函数:
virtual void breathe() = 0;
含有纯虚函数的类叫做抽象类。
抽象类不能声明对象。
派生类中必须完全实现纯虚函数。否则派生类也是抽象类,不能实例化。
无论该覆盖定义是否有virtual关键字,该函数都是虚函数。
函数的覆盖:
1、基类函数必须是虚函数
2、发生覆盖的两个函数分别位于派生类和基类中
3、函数名称与参数列表必须完全相同
函数的隐藏两种情况:
1、派生类的函数和基类的函数完全相同,只是基类的函数没有virtual
2、派生类的函数与基类的函数同名,但参数列表不一样。不管基类的函数有没有virtual,基类的函数都将被隐藏。重载发生在一个类里面。
列表不一样就隐藏了、没有虚函数的事也隐藏了。
列表一样,有虚函数叫覆盖。
记住:函数覆盖,参数列表一样。
记住一句话:函数的覆盖是发生在派生类与基类之间,两个函数必须完全相同,并且都是虚函数,不属于这种情况的就是隐藏了。
覆盖了就不显示了,隐藏了还可以显示。
引用:
引用就是一个变量的别名
int a = 5;
int &b = a; //引用在声明时必须初始化。
引用一旦初始化,它就代表了一块特定的内存,不能再代表其他的内存。
指针是地址。指针变量要存储地址值,因此要占用存储空间。我们可以随时修改指针变量所保存的地址值,从而指向其他的内存。
设计习惯以及头文件重复包含的问题。
<> 和 "" 的区别。<> 和 "" 表示编译器在搜索头文件时的顺序不同。
<> 表示 系统目录、PATH环境变量列出的目录,不搜索当前目录。
"" 当前目录、系统目录、PATH环境变量列出的目录。
条件预处理指令
#ifndef ANIMAL_H_H
#define ANIMAL_H_H
VC++ 程序编译链接的原理与过程
C++对工程中的三个源文件单独进行编译。编译时,先由预处理器对预处理指令进行处理,在内存中输出翻译单元。编译器接受预处理器的输出。将源代码转换成包含机器语言指令的三个目标文件(obj)。接下来链接器将目标文件和标准类库一起链接生成exe文件。