1......virtual关键字:
基函数定义了virtual,继承类的该函数也就具有virtual属性。定义了virtual属性后,如果用基类类型的指针指向子类,可以用该指针直接调用子类中对应的函数。可以说虚函数就是c++多态性的一种体现。
纯虚函数是一种特殊特殊的函数,在基类并不给出有意义的实现,而留给子类实现。
理论上在基类采用virtual关键字,不进行实现就可以实现纯虚函数,拥有纯虚函数的类不能被实例化。但是,如果这种情况下进行了实例化,编译器不能再编译阶段发现问题,只能在链接阶段报错,所以,标准的声明纯虚函数的方法如下:
virtual ~CException() = 0;
这样,一旦声明了该类的实例,就会产生如下错误
错误 C2259 “CException”: 不能实例化抽象类
2.......初始化列表
三种情况下只能使用初始化列表对成员变量进行初始化,而不可以在构造函数中对其初始化。
常量成员,因为常量只能初始化不能赋值,所以必须放在初始化列表里面
引用类型,引用必须在定义的时候初始化,并且不能重新赋值,所以也要写在初始化列表里面
没有默认构造函数的类类型,因为使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数初始化。
对第三种情况,例子如下:
struct Test1
{
Test1(int a):i(a){}
int i ;
};
struct Test2
{
Test1 test1 ;
Test2(Test1 &t1)
{
test1 = t1 ;
}
};
以上代码无法通过编译,因为Test2的构造函数中test1 = t1这一行实际上分成两步执行。
1. 调用Test1的默认构造函数来初始化test1
2. 调用Test1的赋值运算符给test1赋值
但是由于Test1没有默认的构造函数,所谓第一步无法执行,故而编译错误。正确的代码如下,使用初始化列表代替赋值操作。
struct Test2
{
Test1 test1 ;
Test2(Test1 &t1):test1(t1){}
}
3....static
与普通函数相比,静态成员函数由于不是与任何的对象相联系,因此它不具有this指针。从这个意义上讲,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数。
class QList
6...explic关键字
关键字explicit可以禁止“单参数构造函数”被用于自动类型转换
class Stack
{
explicit Stack(int size);
};
没有explicit的话Stack s = 40;能编译通过
而有explicit则不能,必需Stack s(40);
#include <iostream>
using namespace std;
class CExample {
private:
int a;
public:
//构造函数
CExample(int b)
{ a = b;}
//拷贝构造函数
CExample(const CExample& C)
{
a = C.a;
}
//一般函数
void Show ()
{
cout<<a<<endl;
}
};
int main()
{
CExample A(100);
CExample B = A; // CExample B(A); 也是一样的
B.Show ();
return 0;
}
在三种情况下会调用拷贝构造函数(1)对象以值传递的方式作为函数参数时(2)对象以值传递的方式作为函数返回时(3)直接拷贝的
拷贝构造函数可以分为浅拷贝和深拷贝。默认的拷贝构造函数就是浅拷贝。
在浅拷贝时,只处理对象中的数据成员。
如果出现比如说在构造函数中动态在堆中分配了内存空间,注意,浅拷贝的两个对象实际上是公用同一块内存空间,这样在析构时就会出现错误。
深拷贝的代码如下
class Rect
{
public:
Rect() // 构造函数,p指向堆中分配的一空间
{
p = new int(100);
}
Rect(const Rect& r)
{
width = r.width;
height = r.height;
p = new int; // 为新对象重新动态分配空间
*p = *(r.p);
}
~Rect() // 析构函数,释放动态分配的空间
{
if(p != NULL)
{
delete p;
}
}
private:
int width;
int height;
int *p; // 一指针成员
};