翁恺老师视频内容 (C++)

内容来自翁恺老师部分视频

基本语法

类的默认构造函数(default constructor)

不带参数的构造函数就是默认构造函数,包括自己定义的和编译器自动给的auto

#include <iostream>
#include <iostream>

using namespace std;

//创建类,在这里声明类的方法
class A {
public:
    A(string str); //constructor, similar python class __init__()
    ~A(); //destructor
};
//构造函数,同类名
//构造器没有返回值(void也不行),名字和类一样,创建对象时自动调用构造函数
A::A(string str){
    cout << endl << str << endl;
}
//析构函数(destructor),类名加~
//在对象要被消灭之前时调用,无返回值,无参数
A::~A(){
    cout << endl << "----class A will die----" << endl;
}

//在C++中class和struct基本差不多,有细微差别
//在这里相当于定义一个类B,其中声明了B(inta)这个构造器函数
struct B {
    float f;
    int i;
    B(int a);
};
//定义B(inta)构造函数
B::B(int a){
cout << endl <<"struct B init---"<< a << endl;
}

int main()
{
    A a("A__init__OK"); //创建对象a,初始化输入string "A__init__OK"

    //创建一个对象数组b,每个元素是一个初始化后的B对象,都赋值了构造函数的参数
    //B b[2] = {B(1)}; //错误,因为这里只给了第一个元素(对象),告诉编译器再找一个,找不到。。。
    //错误类型在两种编译器中是不一样的:
    //GUN GCC中:main.cpp|39|error: could not convert '<brace-enclosed initializer list>()' from '<brace-enclosed initializer list>' to 'B'|
    //TDM GCC中:39	[Error] no matching function for call to 'B::B()'
    B b[2] = {B(1), B(2)}

    return 0;
}
this

跟python中的self很像

访问权限
#include <iostream>

//访问限制private friend
using namespace std;

class A{
private:
    int i;
    int *p;
public:
    A(){cout << endl << "A::A()";}
    ~A(){cout << endl << "A::~A()";}
    void haha(int ii){i = ii;} //修改私有变量
    void f(A *a){cout << endl << "A::f(A *a) a -> i = " << a->i;} //输出私有变量

};


// friend使用,运算符重载时授权
// 也是在编译时刻检查
struct X;//前向声明

struct Y{
    void f(X*);
};

struct X{ //定义
private:
    int i; //X的私有成员
public:
    void initialize();
    friend void g(X*, int);
    friend void Y::f(X*);
    friend struct Z;
    friend void h();
};
void X::initialize(){
    i = 0;
}
void g(X* x, int j){
    x->i = j;
}
void Y::f(X* x){
    x->i = 47;
}
struct Z{
private:
    int k;
};


int main()
{
    A *p = new A[10]; //开辟一个存放A类型的的数组,并返回指针赋值给p
    A a; //创建a对象
    a.haha(88); //调用a的haha方法设置a私有属性的值
    p[0].f(&a); //p数组第0个元素是一个A对象,调用对象的f方法,传入A类型对象a的指针
                //输出88,private相对于类来说的,同类的对象之间可以相互访问私有属性(私有成员变量)
                //private的限制只在编译时刻,运行时完全无关,面向对象仅在源代码.cpp中成立
    delete[] p;
    return 0;
}
class和struct的区别
class A{
	int i; //默认private
}

struct A{
	int i; //默认public
}
软件重用方式
  1. 重组(composition):已有对象进行组合,用对象制造对象。玩实的。
    包含的方式(内存模型):fully(其他对象就是此其中一部分,其他对象全部在里面)和by reference(只有地址,通过地址访问到其他对象,但不在此内部)
    class Person {;;;};
    class Currency {;;;};
    
    class SavingAccount	{
    public:
    	SavingsAccount ( const char* name,const char* address, int cents );//构造函数
    	~savingsaccount ();//析构函数
    	void print();
    private:
    	Person m_saver; //完全包含别人的对象
    	Currency m_balance; //完全包含别人的对象
    };
    //初始化列表 A::f(): a(0) {} //在构造函数之前就执行a(0)
    //在初始化列表中调用m_saver、m_balance
    SavingsAccount::SavingsAccount (const char* name, const char* address, /
    int cents): m_saver(name, address), m_balance(0, cents) {}
    void SavingsAccount::print() {
    	m_saver. print();
    	m_balance. print();
    }
    
    1).所有成员变量都必须在初始化列表中初始化
    2)父类的构造函数调用也必须在初始化列表中初始化。
    不放在构造函数里面。否则需要默认构造。
  2. 继承(inheritance)
    在已有的基础上做改造。玩虚的,类是虚的。
  • 父类、基类、超类(Parent、Base、Super)
  • 派生类、子类(Derived、Sub、Child)
    子类访问父类的private、protected
    #include <iostream>
    
    using namespace std;
    
    class A {
    public:
        A(): i(0) {cout << "A::A()" << endl;} //成员变量i初始化
        ~A() {cout << "A::~A()" << endl;}
        void print() {cout << "A::f()---" << i << endl;}
    protected: //protected留给子类访问private的数据
        void set(int ii) {i = ii;}
    private:
        int i; //成员变量i
    };
    
    class B: public A { //定义B是A的子类
    public:
        void f() {
            set(20); //子类可以直接用父类protected的东西,但子类的对象不能直接用,但可以间接访问
            print(); //调用父类public函数set()和print()
            //i = 100; 父类私有的在子类中存在,但不能直接使用,尽管i存在,但不能直接使用。
            //error: 'int A::i' is private within this context
        }
    };
    
    int main()
    {
        B b;
        //b.set(1); //子类对象直接访问父类protected,出错。子类可以直接用父类protected的东西,但子类的对象不能直接用,但可以间接访问
        b.print();
        b.f(); //通过f函数间接访问,子类可以直接用父类protected的东西,但子类的对象不能直接用,但可以间接访问
    
        return 0;
    }
    
函数隐藏

父类中有几个不同形式的同名函数(overload。要构成overload,两个同名函数的参数表必须不一样),如果子类中出现与父类同名的函数,只保留子类的函数,父类的函数将被隐藏。

默认参数

默认参数不能写在定义处,应该在声明处,在编译阶段自动补上默认值。尽量不要使用默认参数。

#include <iostream>

using namespace std;

void f(int i=10, char c='A');//默认参数不能写在定义处,应该在声明处

int main()
{
    f();
    return 0;
}

void f(int i, char c) { //默认参数不能写在定义处,应该在声明处
    cout << i << endl << c << endl;
}
内联函数(inline)

类型为inline的函数,只是在编译阶段将这段函数的代码插入到调用的地方,再优化,实际是不存在可执行代码里的。以空间换时间,不再需要堆栈处理,效率高。和宏函数有相似功能,但宏没有类型检查,不安全。

  1. inline函数的body和声明都放在.h文件里面,inline就是声明。递归(需要堆栈)和占用很大空间的函数不能设为内联函数。
    xxx.h
    inline void f();
    inline void f() {
    	cout << "inline f()" << endl;
    }
    
  2. 类的成员函数直接写在类声明里面,默认就是inline,不用.cpp去放类的成员函数的body。
    xxx.h
    class A {
    private:
    	int i;
    public:
    	void f() {cout << "inline f()" << endl;}
    }
    
  3. 类声明,然后在类外面成员函数前写上inline,也是内联函数。
    xxx.h
    class A {
    private:
    	int i;
    public:
    	void f();
    }
    
    inline void f() {cout << "inline f()" << endl;}
    
const

被const的对象一定要初始化

  1. const是变量
extern const int bufsize; //声明外部的全局变量bufsize在这里是const,而bufsize本身不一定是const类型

//做数组大小正确使用
const int a_size = 12;//在编译阶段就完成了size的初始化,
int a[a_size]; //size的值已知,所有这里合法
//错误使用
extern const int b_size;//只告诉编译器外部有这个东西,具体值多少不知道
int b[b_size]; //错误
  1. const与指针
//const与*谁前谁后

char * const q = "abc"; //q是const,q不能被修改
*q = 'd'; //ok,但是q所指的空间是个普通字符变量
q++; //error,q是const

const char *p = "abc"; //*p是const,通过p不能对p所指内容进行修改
*p = 'c'; //error
p++; //ok

Person p1("Fred", 200); 
const Person* p = &p1; //指针是const
Person const* p = &p1; //指针是const
Person *const p = &p1; //对象是const
const Person* const p = &p1; //指针和对象都是const

本地变量在堆栈里面,全局变量在全局数据区,常量在代码段里,代码段不可写。

char *a = "hello world!";//定义了一个指针a,a指向代码段const
char s[] = "hello world!";//定义一个数组s,系统从代码区拷贝const到堆栈区
a[0] = 'a'; //a指向的空间为const空间,在代码段里,可读不可写

3.非const变量当成const变量使用(non-const —> const)

void f(const int* x);
void f(const int* x){ //形参为const类型,函数内部保证不会更改x的对象
    (*x)++; //形参x的对象为const类型,此处会报错error: increment of read-only location '* x'|
    cout << *x << endl;
}
int b = 10;
f(&b);

4.成员函数const

class A {
private:
    int i;
public:
    A():i(0){cout << "A::A()" <<endl;}; //在构造函数中初始化成员变量i
    void ff() const; //声明和定义处都const
};
void A::ff() const { //声明和定义处都const
    i++; //error: increment of member 'A::i' in read-only object
    	 // 不能改变成员变量,相当于this是const
    cout << i << endl;
}
  1. const放在成员函数后面和无const成员函数构成overload关系
class B {
private:
	int i;
public:
    B():i(0) {}
	void f() {cout << "f()" << endl;}
	void f() const {cout << "f const" << endl;}//与上构成overload关系
};
const B b; //由B定义一个const类型的对象b
b.f();//输出f const 因为this为const类型
B bb;
bb.f();//输出f() 因为this为普通类型,调用f()

构成overload关系的关键是两个函数参数表不同。
两个f函数的参数表分别为:

void f(A* this)
void f(const A* this) 
references/alias(引用/别名)

引用 定义时必须必须初始化,引用作为形参时,在函数内部可以直接改变被引用的变量(C只通过指针改变)。本身就是用* const p实现,一经定义,无法改变。引用不是实体。

char c;
char &r = c;//引用初始化为c,与c绑定

int a;
const int& z = a;//z是x的别名(引用),但是不能通过z修改a,跟前面指针一样

int i;
int&j = i;
j = 10;//i跟着变为10

func(int& );
int k=2;
func(k * 3);//报错,func的参数是一个引用,这里k*3不是应用,仅仅是个临时的结果

int&* p;//错误,p定义为指针,
int*& p;//ok,p是引用,p捆绑的变量是个int型指针变量

在这里插入图片描述
在这里插入图片描述

upcasting(向上造型)

把子类当做父类对象看待。向上造型是将派生引用或指针转换为基类引用或指针的操作。向下造型有风险。
在这里插入图片描述
Employee父类,Manager子类
在这里插入图片描述

多态性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值