C++ 基础知识(二)
1.复制构造函数
编译器会默认提供复制拷贝函数,但是也可以显式的定义,形参是本类对象的引用
class point
{
private :
int a;
int b;
public:
point(int x,int y)
{
a=x;
b=y;
std::cout<<"调用构造函数"<<std::endl;
}
point(const point& p) //显式的定义复制构造函数,必须是按引用传参&的形式,const可以不加,最好加
{
std::cout<<"调用复制构造函数"<<std::endl;
a=p.a;
b=p.b;
}
print()
{
std::cout<<a<<b<<std::endl;
}
};
int main()
{
point p1(3,5);
point p2=p1; //可以通过直接赋值的方式,这样会调用复制构造函数
p2.print();
point p2(p1); //也可以通过参数传参的方式,与上面的等价
p2.print();
return 0;
}
有些时候必须显式的定义复制构造函数,比如类中含有指针类的数据成员、需要使用动态内存,最好定义复制构造函数,避免内存错误
2.友元
友元函数:
下面的例子通过友元函数来访问类内部私有成员,该友元函数不属于任何一个类
class point
{
private :
int a;
int b;
public:
point():a(3),b(4)
{
}
show_ab();
friend void show_ab_f(point &p); //声明友元函数
int c=5;
};
point::show_ab()
{
std::cout<<a<<b<<std::endl; //成员函数访问私有对象
}
void show_ab_f(point &p) //定义友元函数,此函数不属于任何类
{
std::cout<<p.a<<p.b<<std::endl; //友元函数访问私有对象
}
int main()
{
point p;
p.show_ab(); //调用成员函数
show_ab_f(p); //调用友元函数,传入point类
std::cout<<p.a<<p.b<<std::endl; //报错,私有对象只能类成员访问
std::cout<<p1.c<<std::endl; //只能访问共有对象
return 0;
}
上面的例子是一个全局函数为point的友元函数,也可以定义一个类的成员函数为另一个类(point)的友元函数
那么该函数既可以访问本类的成员,也可以访问类point的成员,这里就不写例子了
友元类:
友元类,就是一个类(line)是另一个类(point)的友元类,那么友元类(line)的所有成员函数都可以访问point类的所有成员,如下例:
class line; //先声明line类,后面在定义,不然下面point类中不认识line
class point
{
private :
int a;
int b;
friend line; //声明友元类
public:
point():a(3),b(4)
{
}
};
class line //定义line类
{
public:
show(point& p)
{
std::cout<<p.a<<p.b<<std::endl; //访问point的成员
}
};
int main()
{
point p;
line _line;
_line.show(p);
return 0;
}
3.内联函数(inline)
内联函数就是在函数定义前加上inline关键字的函数。
例如A函数调B函数,B函数是内联函数,则编译器会把B函数的函数体复制到A函数里面,A函数里包含了B函数的代码,而B函数则不存在了,从而节省反复调用的函数开销
为什么要用inline?
假设有下列min()函数
int min( int v1, int v2 )
{
return( v1 < v2 << v1 : v2 );
}
为这样的小操作定义一个函数的好处是:
- 如果一段代码包含min()的调用,那阅读这样的代码并解释其含义比读一个条件操作符的实例,可读性会强很多。
- 改变一个局部化的实现比更改一个应用中的300个出现要容易得多
- 语义是统一的,每个测试都能保证相同的方式实现
- 函数可以被重用,不必为其他的应用重写代码
不过,将min()写成函数有一个严重的缺点:如果程序中有很多地方频繁的调用min函数,这样的话,比直接计算条件操作符要慢很多。为什么?
假设A函数中调用了B函数,在调用B函数时,先要中断A函数,将执行流程转移到B函数中,等B函数执行完,再返回A函数,所以在调用B函数前,要保护A函数的现场,记录程序当前位置,以方便从B函数返回,恢复现场,并从原来的位置继续执行. 如果频繁调用,则会影响程序性能
inline 函数正是为了解决这个问题的。总结下:
(1)inline函数就是以空间换时间,是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率
(2)inline函数必须在函数定义前加 inline关键字,声明前加则不起作用
(3)对于像一些短小,调用频繁的函数可以使用inline。对一些很长的函数,或者包含循环,switch,递归的函数不要使用inline。
(4)inline对于编译器来说只是一个建议,编译器可以选择忽略该建议。换句话说,哪怕真的写成了inline, 而且没有错误,编译器也会自动进行优化。所以当inline中出现了递归,循环,或过多代码时,编译器自动无视inline声明,同样作为普通函数调用
4.函数的重载
一个函数有相同的名字,但是传参的形式和返回值不一样,则视为函数的重载
不能出现名字相同,传参相同,仅仅是返回值不同的重载,编译器会报错。
5.继承
(1).基类和派生类:B类继承自 A类,则A类称为基类,B类称为派生类
(2)直接基类和间接基类。 举例孙子继承父亲,父亲继承爷爷。父亲是孙子的基类,也称为直接基类,爷爷是父亲的直接基类。而爷爷是孙子的间接基类。
(3)public继承,protect继承,private继承
public、protected、private方式继承后,成员属性的变化如下表:
(4)多基派生和单基派生
单基派生就是指 派生类只有一个基类。
多基派生就是指 派生类有多个基类,既同时继承多个基类,C++ 支持多继承