面向对象的四个重要特性,抽象,封装,继承和多态。而类就是对现实事物的抽象,包括属性和方法。
class 类名
{
public:
公有成员
protected:
保护成员 // protected 和 private 的区别就是派生类成员是否可以访问
private:
私有成员 // 若是直接跟在类名之后定义,则 private 关键字可以省略,即默认为 private
};
class Clock
{
int hour, minute, second;
public:
void set_time(int h, int m, int s);
void show_time();
};
void Clock::set_time(int h, int m, int s)
{
this->hour = h;
this->minute = m;
this->second = s;
}
void Clock::show_time()
{
printf("%d:%d:%d\n", this->hour, this->minute, this->second);
}
在定义一个对象时,由系统自动调用的初始化函数。构造函数无返回值,且与类同名。
若没有自定义构造函数,编译器会默认生成一个无参的构造函数,其中构造函数可以重载,带默认参数等。但是一旦自定义了构造函数,编译器就不会生成默认的无参的构造函数。
拷贝构造函数时一种特殊的构造函数,其参数是本类对象的引用,当用一个对象去初始化另一个对象,函数参数传递,函数返回类对象等时,系统会调用拷贝构造函数。
同构造函数,若没有自定义构造函数,编译器会默认生成一个的拷贝构造函数。
当对象内存被释放时被自动调用,同理,编译器也会默认生成一个析构函数。
class Clock
{
int hour, minute, second;
public:
Clock(); // 默认的构造函数
Clock(int h, int m, int s); // 自定义构造函数
Clock(Clock &c); // 拷贝构造函数
~Clock(); // 析构函数
void set_time(int h, int m, int s);
void show_time();
};
Clock::Clock()
{
cout << "默认构造函数被调用" << endl;
}
Clock::Clock(int h, int m, int s): hour(h), minute(m), second(s)
{
cout << "自定义构造函数被调用" << endl;
}
Clock::Clock(Clock &c)
{
this->hour = c.hour;
this->minute = c.minute;
this->second = c.second;
cout << "拷贝构造函数被调用" << endl;
}
Clock::~Clock()
{
cout << "析构函数被调用" << endl;
}
静态成员以static
修饰,其含义不再依附于对象存在,而是属于类本身,是类共有的属性和函数。
public
,且在类外初始化,用::
指明其所属类。在类外初始化时要指明变量类型。static
class Clock
{
int hour, minute, second;
public:
static int count;
static int get_count();
Clock(); // 默认的构造函数
Clock(int h, int m, int s); // 自定义构造函数
Clock(Clock &c); // 拷贝构造函数
~Clock(); // 析构函数
void set_time(int h, int m, int s);
void show_time();
};
int Clock::count = 0;
int Clock::get_count()
{
return Clock::count;
}
友元是 CPP 提供的一种破坏数据封装性的机制。通过声明 B 是 A 的友元类或友元函数,B 可以访问 A 的private
属性和函数。
所以友元是基于类的,因为只有类才有private
属性。
友元关系是单向的,不可以继承。
class Point
{
int x, y;
public:
friend float dist(Point a, Point b);
};
float dist(Point a, Point b)
{
double dx = a.x - b.x;
double dy = a.y - b.y;
return sqrt(x*x, y*y);
}
class A
{
public:
friend class B;
private:
int x, y;
};
CPP 支持多继承。
class 派生类名: 继承方式1 基类名1, 继承方式2 基类名2
{
// xx
};
public
)
public
和protected
在派生类中的属性不变,private
属性不变。public
和protected
。public
。private
)
public
和protected
在派生类中均为private
,private
属性不变。public
和protected
。protected
)
public
和protected
在派生类中均为protected
,private
属性不变。public
和protected
。class A
{
int a;
public:
A();
A(int a);
int get_a(){return a;}
};
A::A()
{
cout << "A的默认构造函数被调用" << endl;
}
A::A(int a) : a(a)
{
cout << "A的自定义构造函数被调用" << endl;
}
class B : public A
{
public:
B();
B(int a);
};
B::B()
{
cout << "B的默认构造函数被调用" << endl;
}
B::B(int a): A(a)
{
cout << "B的自定义构造函数被调用" << endl;
}
当派生类与基类有成员变量同名时:
a.Base1::var
在多继承时,出现同名成员时,可以通过同名隐藏规则和虚基类解决。
class A
{
public:
void f();
};
class B
{
public:
void f();
void g();
};
class C : public A, public B
{
};
// c.f() // 此时,就会出现二义性,可以通过同名隐藏规则解决
c.A::f()
c.B::f()
还有另一种情况,当派生类从多个基类派生,而这些基类又从同一个基基类派生,则在访问基基类所拥有的成员变量时,就会产生二义性,这是需要用到虚基类解决。
class B
{
public:
int b;
};
class B1 : public B {};
class B2 : public B {};
class C : public B1, public B2 {};
c.b // 出现二义性问题,request for member ‘b‘ is ambiguous
虚基类用于解决拥有共同基类的二义性问题。在继承时共同基类时加virtual
即可。
虚基类继承时,只为最远的派生类提供唯一的基类成员,不会产生重复。这里的最远派生类是指定义对象时所指定的类的基基类,此时共同成员由最远派生类来初始化。
class B
{
public:
int nv;
B(){}
B(int n){ nv = n; cout << "Member of B" << endl; }
void fun(){ cout << "fun of B" << endl; }
};
class B1 : virtual public B {};
class B2 : virtual public B {};
class C :public B1, public B2
{
public:
C(int a) :B(a){ cout << "Member of C" << endl; }
};
c.nv // 1
c.fun() // fun of B
多态是同一事物在不同条件下的执行结果不同。在 CPP 中,实现多态有 3 中方法,函数重载,运算符重载和虚函数。
函数名相同,函数的参数个数或者参数类型或者参数顺序不同,则称之为函数重载。
函数的返回值类型不可以作为判断函数重载的依据。
CPP 中的子类也可以自动向上转型,即子类可以当做父类用,但是此时只能使用从父类继承的成员,调用的函数也是父类的函数体,没有实现动态绑定。在 CPP 中要实现动态绑定,则需要用到虚函数+指针/引用
virtual
即可。class A
{
public:
virtual void fun(){cout << "fun of A" << endl;}
};
class B : public A
{
public:
void fun() { cout << "fun of B" << endl;}
};
void allfun(A &a)
{
a.fun();
}
int main(void)
{
B b;
allfun(b); // 如果 void allfun(A a),则结果仍为 "fun of A"
return 0;
}
虚函数 = 0;
模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。模板是创建泛型类或函数的蓝图或公式。库容器,比如迭代器和算法,都是泛型编程的例子,它们都使用了模板的概念。
template <typename type1, typename type2>
ret_type func_name(parameter list)
{
// 函数的主体
}
其中的 type1 和 type2 等是函数所使用的数据类型的占位符名称,这个名称可以在函数定义中使用,代表某一类类型。一个模板里面可以定义多个类型占位符。
#include <iostream>
#include <string>
using namespace std;
template <typename T>
T Max (T const& a, T const& b)
{
return a < b ? b:a;
}
int main ()
{
int i = 39;
int j = 20;
cout << "Max(i, j): " << Max(i, j) << endl;
double f1 = 13.5;
double f2 = 20.7;
cout << "Max(f1, f2): " << Max(f1, f2) << endl;
string s1 = "Hello";
string s2 = "World";
cout << "Max(s1, s2): " << Max(s1, s2) << endl;
return 0;
}
// 在模板定义语法中关键字 class 与 typename 的作用完全一样
template <class type>
class class_name
{
// 类声明
}
#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>
using namespace std;
template <class T>
class Stack {
private:
vector<T> elems; // 元素
public:
void push(T const&); // 入栈
void pop(); // 出栈
T top() const; // 返回栈顶元素
bool empty() const { // 如果为空则返回真
return elems.empty();
}
};
template <class T>
void Stack<T>::push (T const& elem)
{
// 追加传入元素的副本
elems.push_back(elem);
}
template <class T>
void Stack<T>::pop ()
{
if (elems.empty()) {
throw out_of_range("Stack<>::pop(): empty stack");
}
// 删除最后一个元素
elems.pop_back();
}
template <class T>
T Stack<T>::top () const
{
if (elems.empty()) {
throw out_of_range("Stack<>::top(): empty stack");
}
// 返回最后一个元素的副本
return elems.back();
}
int main()
{
try {
Stack<int> intStack; // int 类型的栈
Stack<string> stringStack; // string 类型的栈
// 操作 int 类型的栈
intStack.push(7);
cout << intStack.top() <<endl;
// 操作 string 类型的栈
stringStack.push("hello");
cout << stringStack.top() << std::endl;
stringStack.pop();
stringStack.pop();
}
catch (exception const& ex) {
cerr << "Exception: " << ex.what() <<endl;
return -1;
}
return 0;
}
原文:https://www.cnblogs.com/zghong/p/14149149.html