1:类的构造和析构、友元函数
C++是基于c扩展,增加了面向对象的语言。
面向对象多了类,我们看c++如何创建类
新建头文件student.h
在student.h中 创建一个student.class
#pragma once
#ifdef Student_H
#endif Student_H
class Student {
int i;
public:
//构造方法
Student();
//析构函数
~Student();
private:
int j;
protected:
int k;
private:
int l;
};
在student.cpp中使用
#include "student.h"
#include<iostream>
using namespace std;//引入一个std的命名空间 这是一个标准的输入输出的
//因为在.h中声明了构造方法和析构方法 所以我们需要声明构造方法
Student::Student() {
cout << "构造方法" << endl;
}
Student::~Student() {
cout << "析构方法" << endl;
}
在主cpp中调用
#include <iostream>
#include "student.h"
int main()
{
Student student;
std::cout << "Hello World ! \n";
}
打印结果:
总结:
调用过程:
新建student.h文件,创建student对象(class对象),再创建student.cpp,在cpp中引用student.h,然后实例化student对象。即实现他的构造方法。然后在主程序,即main方法中构建直接调用。我们可以看到打印过程,
先通过对象的构造方法创建了student对象,然后调用main方法的hello word,当主cpp销毁的时候,再去调用student的析构函数销毁对象。
构造方法和析构函数成对出现。
析构函数是系统自己调用的。当系统销毁的时候自动调用析构函数。
我们可以在构造方法中申请内存,可以在析构函数中销毁内存。
我们看一下如何传参和销毁
#ifdef Student_H
#endif Student_H
class Student {
int i;
public:
//构造方法
Student();
//构造方法中也可以通过:i(i)的形式也行
Student(int i, int j):i(i) { };
// this->i;可以这样传参
void setJ(int i);
//析构函数
~Student();
private:
int j;
protected:
int k;
private:
int l;
};
#include "student.h"
#include<iostream>
using namespace std;//引入一个std的命名空间 这是一个标准的输入输出的
//因为在.h中声明了构造方法和析构方法 所以我们需要声明构造方法
Student::Student() {
cout << "构造方法" << endl;
}
void Student::setJ(int i) {
this->i;
cout << i << endl;
}
Student::~Student() {
cout << "析构方法" << endl;
}
#include <iostream>
#include "student.h"
int main()
{
Student student;
int i = 10;
student.setJ(i);
std::cout << "Hello World ! \n";
}
打印结果:
2:友元函数:
当我们修改private的成员变量时,结尾使用const结尾。表示:不会也不允许修改类中的成员,用于优先级比较高的
private:
int j;
int m;
void setM(int m )const;
在student.cpp中调用这个方法的时候报错:
void Student::setM(int m)const {
this->m =m;//这行报错==表达式必须是可修饰的成员变量 只能做简单的读取 但是不能修改 我们把这种函数叫常量函数
cout << a << endl;
}
那么我们该如何修改呢?如何才能在main函数中修改私有变量呢?
void test(Student * stu){
//如何去访问
stu->m = 100;//这里的m也是私有的 报错 不能调用
}
使用友约函数,一般在需要暴露的地方声明友约函数
l例如:在student.h中添加需要在main函数中调用的函数
class Student {
friend void test(Student student);
然后就可以在main中的调用就不报错了
int main()
{
Student student;
int i = 11;
int m= 101;
student.setJ(i);
student.setM(m);
test(&student);//调用这个函数
std::cout << "Hello World ! \n";
}
3:友元类
class CCar
{
private:
int price;
friend class CDriver; //声明 CDriver 为友元类
};
class CDriver
{
public:
CCar myCar;
void ModifyCar() //改装汽车
{
myCar.price += 1000; //因CDriver是CCar的友元类,故此处可以访问其私有成员
}
};
int main()
{
return 0;
}
2:单例对象,操作符重载
C++也有单例模式
studnent.h
#pragma once
class Student {
static Student* instance;
Student();
public:
static Student* getInstance();//指针在声明的时候或者使用之前必须初始化
};
student.cpp
#include "Student.h"
//Student* instance = 0;//怎么声明他是Student下的instance
Student* Student::instance = 0;//这样声明表示是student下的instance
Student* Student::getInstance() {
if (! instance)
{
instance = new Student();
}
return instance;
}
main:
#include <iostream>
#include "Student.h"
int main()
{
Student* studnet = Student::getInstance();//C++调用方法是使用::
std::cout << "Hello World!\n";
}
2:重载
1:重载函数
2:操作符重载,这是java不支持的
#pragma once
class test {
public:
int i;
test operator + (const test) {
test temp;
temp.i = this->i + i;
return temp;
}
};
int main()
{
test test1;
test1.i = 100;
test test2;
test2.i = 200;
test test3 = test1 + test2;
}
运行等于300
3:继承多态,虚函数
C++ 可以实现多继承 通过: 号实现继承
#pragma once
class Child :Parent{
};
class Parent {
};
我们还可以指定继承的修饰符
#pragma once
class Child :public Parent{};
class Parent {
public:
void test() {};
};
我们在main函数中调用正常
#include <iostream>
#include "Instance.h"
int main()
{
std::cout << "Hello World!\n";
Child child;
child.test;
}
如果改成private Parent 就不能正常调用了
private只能继承私有继承
#pragma once
using namespace std;
class Parent {
public:
void test() {
cout << "parent1" << endl;
}
};
class Child : public Parent{
public:
void test() {
cout << "child" << endl;
}
};
#include <iostream>
#include "Instance.h"
int main()
{
std::cout << "Hello World!\n";
Child child;
child.test();
}
他会调用子类的方法 而不是去调用父类的。
那么如果我们需要使用父类的该如何定义呢?
#include <iostream>
#include "Instance.h"
int main()
{
std::cout << "Hello World!\n";
Parent* child = new Child();
child ->test();
}
这样虽然是new 的子view,他并不是等编译执行完了再去确定类型,而是初始化的时候就确定了类型,所以他还是指向parent1
可以在Child的子view中再调用一下父类的方法就可以了
class Child : public Parent{
public:
void test() {
Parent::test();
}
};
2:多态
多态分为静态多态和动态多态
1 class Derived1:public Base
2 {};
3 class Derived2:public Base
4 {}:
5 int main()
6 {
7 Derived1* p1 = new Derived1;
8 Base = p1;
9 Derived2* p2 = new Derived1;
10 Base = p2;
11 return = p2
12 }
静态多态也称为静态绑定或早绑。编译器在编译期间完成的, 编译器根据函数实参的类型(可能会进行隐式类型转换) , 可推断出要调用那个函数, 如果有对应的函数就调用该函数, 否则出现编译错误。
动态多态
动态绑定: 在程序执行期间(非编译期) 判断所引 用对象的实际类型, 根据其实际类型调用相应的方法。使用virtual关键字修饰类的成员 函数时, 指明该函数为虚函数, 派生类需要重新实现, 编译器将实现动态绑定。
这里的virtual相当于abstract关键字 需要子类 派生类必须重新实现的声明。
4:泛型
泛型基础 模板编程
函数模板 java 的泛型方法
template <typename T>
T a(T i, T j) {
return i > j ? i : j;
}
类模板
class Q {
public:
T test(T t, T e) {
}
};
int main()
{
Q<int, float>a;
std::cout << a.test(1, 1.1f);
}
5:强转
C的强转:
C的风格强制类型转换(Type Cast)很简单,不管什么类型的转换统统都是 TYPE a(TYP)b;
C++的风格的类型转换提供了四种类型转换操作符来应对不同场合的应用
强转类型;
1:const_cast,字面上理解就是去const属性 const属性类似于java的final关键字
2:static_cast:命名上理解就是静态类型转换,如int转换成char
3:dynamic_cast:命名上理解就是动态类型转换,如子类和父类之间的动态类型转换
4:reinterpret_cast:仅仅重新解释类型,单没有进行二进制转换
例子
类型转换
const char* a;
char* b = const_cast < char* > (a);
static_cast;
1:基础类型之间互转,如 float 转成int int 转成unsigned int 等等
2:指针域voud之间互转,如float*,Bean*转成void* 函数指针转成void*
3:子类指针/引用与父类指针/引用转换
dynamic_cast
主要将基类指针,引用安全的转为派生类
在运行期间对可以的转型操作进行安全检查 仅对多态有效
6:异常
跟java差不多 都是try catch throw Exception
7:文件与流操作
C语言的文件读写操作
头文件stdio.h
函数类型:FILE*fopen(const char *path,const char * mode);
path:操作的文件路径
mode:模式:
C++文件读写操作
<iostream>和<fstream>
7:容器
容器:stl:标准模板库
分类:序列式与关联式
序列式容器:元素排列顺序与原诉本身无关,有添加顺序决定的 例如java的stack
Vector,list dequeue queu,stack priotity queue
2:关联式容器:-------java的集合也需要总结看一下 主要看 创建,存储 ,获取,删除等操作即可。
set map hashmap
8:命名空间 namespace
因为c++没有分包的概念,所以但我们出现重复命名的时候就无法编译通过,所以我们可以通过命名空间来实现
看下面的例子: