面向对象的三大特征是封装、继承、多态。
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。封装本质上是一种管理,不想给别人看到的,我们protected/private把成员封装起来。开放一些共有的成员函数对成员合理的访问。
多态:用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。实现多态,有二种方式,重写,重载。
#include
using namespace std;
class A {
public:
virtual void fun() {
cout << "A";
}
};
class B : public A
{
public:
virtual void fun() {
cout << "B";
}
};
int main(void)
{
A* a = new B();
a->fun();//输出B,A类中的fun在B类中重写
}
#include
using namespace std;
class A
{
void fun() {};
void fun(int i) {};
void fun(int i, int j) {};
void fun1(int i,int j){};
};
C++中的构造函数可以分为4类:默认构造函数、初始化构造函数、拷贝构造函数、移动构造函数。
class Student
{
public:
//默认构造函数
Student() {
num=1001;
age=18;
}
//初始化构造函数
Student(int n,int a):num(n),age(a){}
private:
int num;
int age;
};
int main() {
//用默认构造函数初始化对象S1
Student s1;
//用初始化构造函数初始化对象S2
Student s2(1002,18);
return 0;
}
#include "iostream.h"
class Test {
int i;
int *p;
public:
Test(int ai,int value) {
i = ai;
p = new int(value);
}
~Test() {
delete p;
}
Test(const Test& t) {
this->i = t.i;
this->p = new int(*t.p);
}
};
//复制构造函数用于复制本类的对象
int main(int argc, char* argv[])
{
Test t1(1,2);
Test t2(t1);//将对象t1复制给t2。注意复制和赋值的概念不同
return 0;
}
赋值构造函数默认实现的是值拷贝(浅拷贝)。
3. 移动构造函数。用于将其他类型的变量,隐式转换为本类对象。下面的转换构造函数,将int类型的r转换为Student类型的对象,对象的age为r,num为1004。
Student(int r)
{
int num=1004;
int age= r;
}
只定义了析构函数,编译器将自动为我们生成拷贝构造函数和默认构造函数。
默认构造函数和初始化构造函数。 在定义类的对象的时候,完成对象的初始化工作。
class Student
{
public:
//默认构造函数
Student() {
num=1001;
age=18;}
//初始化构造函数
Student(int n,int a):num(n),age(a){}
private:
int num;
int age;
};
int main()
{
//用默认构造函数初始化对象S1
Student s1;
//用初始化构造函数初始化对象S2
Student s2(1002,18);
return 0;
}
有了有参的构造了,编译器就不提供默认的构造函数。
拷贝构造函数。
#include "iostream.h"
class Test {
int i;
int *p;
public:
Test(int ai,int value) {
i = ai;
p = new int(value);
}
~Test() {
delete p;
}
Test(const Test& t) {
this->i = t.i;
this->p = new int(*t.p);
}
};
//复制构造函数用于复制本类的对象
int main(int argc, char* argv[])
{
Test t1(1,2);
Test t2(t1);//将对象t1复制给t2。注意复制和赋值的概念不同
return 0;
}
class HasPtr
{
public:
HasPtr(const string& s = string()) :ps(new string(s)), i(0) {}
~HasPtr() { delete ps; }
private:
string * ps;
int i;
};
HasPtr f(HasPtr hp)
{
HasPtr ret = hp;
///... 其他操作
return ret;
}
如果类外面有这样一个
当函数执行完了之后,将会调用hp和ret的析构函数,将hp和ret的成员ps给delete掉,但是由于ret和hp指向了同一个对象,因此该对象的ps成员被delete了两次,这样产生一个未定义的错误,所以说,如果一个类定义了析构函数,那么它要定义自己的拷贝构造函数和默认构造函数。
定义一个空类:
class Empty {
};
Empty(const Empty& copy) {
}
Empty& operator = (const Empty& copy) {
}
~Empty() {
}
由于派生类重写基类方法,然后用基类引用指向派生类对象,调用方法时候会进行动态绑定,这就是多态。
include<iostream>
using namespace std;
int Add(int a,int b)//1 {
return a+b;
}
char Add(char a,char b)//2 {
return a+b;
}
int main() {
cout<<Add(666,888)<<endl;//1
cout<<Add('1','2');//2
return 0;
}
#include
using namespace std;
// #1 模板定义
template<class T>
struct TemplateStruct {
TemplateStruct() {
cout << sizeof(T) << endl;
}
};
// #2 模板显示实例化
template struct TemplateStruct<int>;
// #3 模板具体化
template<> struct TemplateStruct<double> {
TemplateStruct() {
cout << "--8--" << endl;
}
};
int main() {
TemplateStruct<int> intStruct;
TemplateStruct<double> doubleStruct;
// #4 模板隐式实例化
TemplateStruct<char> llStruct;
}
类中的成员可以分为三种类型,分别为public成员、protected成员、public成员。类中可以直接访问自己类的public、protected、private成员,但类对象只能访问自己类的public成员。
移动也使用一个对象的值设置另一个对象的值。移动实现的是对象值真实的转移(源对象到目的对象):源对象将丢失其内容,其内容将被目的对象占有。移动操作的发生的时候,是当移动值的对象是未命名的对象的时候。这里未命名的对象就是那些临时变量,甚至都不会有名称。典型的未命名对象就是函数的返回值或者类型转换的对象。