面向对象的基本特征:
1、抽象:从具体到一半的过程。抓住事物的本质,而不是内部的具体实现细节。
2、封装:把对象的属性和操作结合在一起,构成一个独立的对象;对外提供一定的接口,在对象之外只能通过接口对对象进行操作;封装增加了对象的独立性,从而保证了数据的可靠性;
3、继承:表达了对象的一般与特殊的关系。特殊类的对象具有一般类的全部属性和服务。当定义一个类后,又需要定义一个新
类,这个新类与原来的类相比,只是增加或修改了部分属性和操作,这时可以用原来的类派生出新类,新类中只需要描述自己所特有的属性和操作。继承简化了对问题的描述,大大提高了程序的可重用性。
4、多态:同一个消息被不同的对象接收时,产生不同的结果,即实现同一个接口,不同方法。一般类中定义的属性和服务,在特
殊类中不改变其名字,但通过各自不同的实现后,可以具有不同的数据类型或不同的行为。
继承和多态性组合,可以生成很多相似但又独一无二的对象。继承性使得这些对象可以共享许多相似特性,而多态又使同一个操作对不同对象产生不同表现形式。这样不仅提高了程序设计的灵活性,而且减轻了分别设计的负担。
内联函数:
内联函数能够提高运行效率,将代码直接嵌入到调入的地方,从而减少了函数调用的开销。程序的体积会增大,以空间换时间。
两种方法实现内联:1、在类中声明,在实现的时候加上inline关键字; 2、在类中直接实现,即使没有加上inline关键字
函数可进行重载,要求相同的作用域。成员函数可以进行重载,要求在类作用域当中。
c++中结构体可以有成员函数。
class与struct的区别:struct默认的是私有成员,struct默认是共有成员。
类的作用域:
1、每个类都定义了自己的作用域称为类作用域;
2、类作用域中说明的标识符只在类中可见。
类作用域:作用域在在类内部
块作用域:作用域在花括号内的,不会影响块作用域外部的变量
文件作用域:在任何代码之外的作用域,在定义的地方到文件结尾有效
函数原型作用域:int Add(int a ,int b) a,b作用域为函数原型作用域,所以在函数定义和函数声明的地方可以同名
函数作用域:在函数内部,主要用于goto语句
前向声明:
1、c++中类必须先定义,才能够实例化。
2、两个类需要相互引用形成一个“环形”引用时,无法先定义适用。这时候需要前向引用。
3、前向声明的类不能实例化
类的嵌套,嵌套类被隐藏在外围类中,该类名只能在外围类中使用。
//类的嵌套
class Outer
{
class Inner
{
public:
void fun()
{
cout << "Inner::fun..." << endl;
}
};
public:
Inner obj_;
void Fun()
{
cout << "Outer::fun.." << endl;
obj_.fun();
}
};
int main()
{
Outer o_;
o_.Fun();
system("Pause");
return 0;
}
如果在外围类的作用域使用该类名时,需要加类的作用域运算符。嵌套类的成员函数可以定义在外围类之外定义。
class Outer
{
class Inner
{
public:
void fun();
};
public:
Inner obj_;
void Fun()
{
cout << "Outer::fun.." << endl;
obj_.fun();
}
};
void Outer::Inner::fun()
{
cout << "Inner::fun.." << endl;
}
int main()
{
Outer o_;
o_.Fun();
system("Pause");
return 0;
}
嵌套类的成员函数对外围类的成员没有访问权,反之亦然。
类也可以定义在函数体内,这样的类被称为局部类。局部类只在定义它的局部域内可见。
局部类的成员函数必须被定义在函数类体内。
局部类中不能有静态成员。
void fun()
{
class LocalClass
{
public:
void Init(int num)
{
num_ = num;
}
void Display()
{
cout << "num_=" << num_ << endl;
}
private:
int num_;
//static int num2_; // 局部类中不能定义静态成员
};
LocalClass LC_;
LC_.Init(5);
LC_.Display();
}
构造函数:
构造函数是特殊的成员函数;
创建类的新对象,系统自动会调用析构函数;
构造函数是为了保证对象的每个数据成员都被正确初始化;
1、函数名与类名完全相同
2、不能定义构造函数的类型(返回类型),也不能使用void
3、通常构造函数被声明为共有的,否则不能被显式的调用。私有构造函数也有其用途。
4、构造函数可以有任意类型和任意个数的参数,一个类可以有多个构造函数(重载)
当没有声明构造函数,类中会自动生成不带参数的构造函数。当声明带参数的构造函数时,类就不会自动生成不带参数的构造函数,此时,可以显式的声明构造函数。
全局对象的构造先于main函数
Test t(10); //全局对象的构造先与main函数
int main()
{
cout << "main start.." << endl;
}
在栈区创建的对象,在生存周期结束时会自动调用析构函数,在堆上创建的对象,要由程序员显式调用delete来释放,同时调用析构函数。
//全局对象的构造先与main函数
int main()
{
Test t[2] = { 10,20 };
Test *p1 = new Test(2);
delete p1; //delete显式调用该释放对象,同时调用析构函数
Test *p2 = new Test[2];
delete[] p2;
cout << "main start.." << endl;
}
构造函数作用:
初始化;
转换构造函数;
int main()
{
Test t1(10); //带一个参数的构造函数,充当的是普通构造函数的功能
t1 = 30; //将20这个整数赋值给t1对象
//1、调用转换构造函数将20这个整数转换成类类型,生成一个临时对象
//2、将临时对象赋值给t对象
Test t2 = 20; //等价于Test t2(20); 这里的不是运算符,表示初始化
cout << "main start.." << endl;
return 0;
}
class Test
{
public:
void Display();
Test& operator=(const Test& other);
Test();
Test(int num);
~Test();
private:
int num_;
};
Test& Test::operator=(const Test& other)
{
num_ = other.num_;
cout << "Test::operator=" << endl;
return *this;
}
int main()
{
Test t1(10); //带一个参数的构造函数,充当的是普通构造函数的功能
t1 = 30; //将20这个整数赋值给t1对象
//1、调用转换构造函数将20这个整数转换成类类型,生成一个临时对象,此时的=已经被重载
//2、将临时对象赋值给t对象,再销毁新建的临时变量
Test t2 = 20; //等价于Test t2(20); 这里的不是运算符,表示初始化
cout << "main start.." << endl;
return 0;
}
explicit,只提供给类的构造函数使用的关键字
编译器不会把声明为explcit的构造函数用于隐式转换,它只能在程序diamante中显式创建对象
在构造函数初始化列表进行数据成员初始化
Clock::Clock(int hour , int minute ,int second :hour_(hour),minute_(minute),second_(second))
构造函数的执行分为两个阶段:
1、初始化段
2、普通计算段
class Object
{
public:
Object(int num) :num_(num) //数据成员初始化
{
cout << "Object..." << endl;
}
~Object()
{
cout << "~Object..." << endl;
}
private:
int num_;
};
class Container
{
public:
Container(int obj1 = 0, int obj2 = 0) :obj1_(obj1), obj2_(obj2) //初始化列表中进行初始化
{
cout << "Container..." << endl;
}
~Container()
{
cout << "~Container..." << endl;
}
private:
Object obj1_; //没有默认的构造函数,需要在之前对构造函数进行初始化赋值
Object obj2_;//缺省传参,使用默认值
};
const数据成员只能在构造函数初始化列表中进行初始化
引用成员也只能在构造函数初始化列表中进行初始化
对象成员(对象所对应的类没有默认构造函数)的初始化,也只能在构造函数初始化列表中进行
class Object
{
public:
Object(int num) :num_(num),knum_(30),refnum_(num_) //对象成员初始化
{
cout << "Object..." << endl;
}
~Object()
{
cout << "~Object..." << endl;
}
private:
int num_;
const int knum_;
int &refnum_;
};
const只能对每个对象来说是常量,不适用所有对象,枚举则使用于所有对象
class Object
{
public:
enum E_TYPE
{
TYPE_A = 100, //枚举只有逗号分隔
TYPE_B = 200
};
public:
Object(int num) :num_(num),knum_(30),refnum_(num_) //对象成员初始化
{
cout << "Object..." << endl;
}
~Object()
{
cout << "~Object..." << endl;
}
void Displayknum()
{
cout << "knum_=" << knum_ << endl;
}
private:
int num_;
const int knum_;
int &refnum_;
};