c++面向对象 梭哈

c++ 面向对象学习笔记

代码格式

头文件的写法

防卫式声明 gurad

ifndef __COMPLEX__  #这个名次是自己取的
#define __COMPLEX__
.   #前置声明
.   #类-声明
.   #类-定义
#endif 

标准库中基于对象的两个典型案例

类中不带指针(复数complex)

#include <iostream>
using namespace std;

// 同一个class的各个object(对象)互为友元  可以直接用另一个对象的pricvate的数据
class complex
{
public: //公开
    complex(double r = 0, double i = 0)
        : re(r), im(i)
    {  }
    complex& operator += (const complex&);
// const 指这个函数不能改变对象里面的数据 传入的参数加const 指不能改变参数的数值
// const 放在类的前面是常对象 只能调用类的 const 成员(包括 const 成员变量和 const 成员函数)
    double real () const { return re; }      
    double imag () const { return im; }      

private:
    double re,im;
// 声明一个全局函数的友元
    friend complex& __doapl ( complex*, const complex& );
};

inline complex& 
__doapl (complex* ths, const complex& r)
{
    ths->re += r.re;
    ths->im += r.im;
    return *ths;
}

inline complex&
complex::operator += (const complex& r)
{
    return __doapl (this, r);
}

// cout 重载只能是作为友元函数,或者是全局函数,因为成员函数的调用是需要由这个对象引发的,而重载的符号只能作用在它前一个类型上,
// 也就是说当作为成员函数的时候必须要是 obj<<cout ,这样才能告诉编译器去成员函数里面去找重载类型,显然这样写是十分反人类的
ostream&
operator << (ostream& os, const complex& x)
{
    return os << '(' << x.real() << ',' << x.imag() << ')';
}

int main()
{
    complex c(1,2);
    cout << c;

    return 0;
}

类中带有指针的(字符串string)

#include <iostream>
#include <string.h>
using namespace std;
#ifndef __MYSTRING__
#define __MASTRING__ 

class String
{
public:
    String(const char* cstr = 0);
    String(const String &str);
    ~String( );
    String& operator = (const String& str);
    char * get_c_str() const { return m_date; }
private:
    char * m_date;
};

#endif

inline
String::String(const char* cstr = 0)
{
    if (cstr) {
        m_date = new char [ strlen(cstr)+1];
        strcpy(m_date, cstr);
    }
    else {
        m_date = new char [1];
        * m_date = '\0';
    }
}

inline
String::~String()
{
    delete[] m_date;
}

inline
String::String(const String &str)// string a(b)    c++新创建的东西会自动调用构造函数    string a = b 一样
{
    m_date = new char [strlen(str.m_date)+ 1];
    strcpy(m_date, str.m_date);
}

inline
String & String::operator= (const String & str)
{
    if (this == &str)  // 检验自我赋值
        return *this;
    delete[] m_date;
    m_date = new char [strlen(str.m_date)+ 1];
    strcpy(m_date, str.m_date);
    return *this;
} 

inline
ostream & operator << (ostream & os, const String & str)
{
    os << str.get_c_str();
    return os;

int main(){
    return 0;
}

类与类之间的关系

复合(Composition)

例子: 表示has-a

一个类复合另一个功能更强大的类只开放这个类的部分功能(开放的这个类与调用的类同时加载)

Untitled

构造由内向外构造

Untitled

在掉用内部的构造函数时编译器只会调用默认构造函数,如果想要调用其他构造函数想要在外层的构造函数里面调用

析构由外向内析构

Untitled

Untitled

代码实现

tempale <class T>
class quene{
...
protected:
	deque<T> c;
public:
	bool empty() const { return c.empty(); }
	size_type size() const { return c.size(); }
	reference front() { return c.front(); }
	referrece back() { return c.back(); }

	void push (const value_type& x) { c.push_back(x); }
	void pop() { c.pop_front(); }
}

委托(Delegation)

composition by reference

例子:

编译防火墙,客户端与实现类分离(reference counting)

Untitled

用指针调用其他类(只有在调用的时候才会构造这个类,用指针相连寿命不一致

Untitled

代码实现

class StringREp;
class String {
public:
	String();
	String(const char *s);
	String(const String& s);
	String &operator=(const String& S);
	~String ();
pricvate:
	StringRep *rep;
}

继承(Inheritance)

继承语法:(is a关系)

Untitled

父类的数据是可以完美继承下来的

子类的对象会有父类的成分

Untitled

调用构造函数与析构函数的情况与复合关系时相似,调用的是默认构造函数

Untitled

Untitled

代码实现

struct _List_ndoe_base
{
	_List_node_base* _M_next;
	_List_node_base* _M_prev;
};

tmplate<typename _Tp>
stuct _List_node
	:public _list_ndoe_base // 三种继承方式public是一种
{
	_Tp _M_date;
}

类中三种访问权限

public 类内可以用,类外可以访问

protected 类内可以访问 类外不可以访问

private 类内可以访问 类外不可以访问

两者主要在继承的时候有区别

在派生类中protected的数据可以访问,而private不能访问,通过类创建出来的对象也无法访问

struct 与 class 区别

最本质的一个区别就是默认的访问控制:默认的继承访问权限

struct是public的,class是private的。

struct A
{
  char a;
};
struct B : A
{
  char b;
}

这个时候B是public继承A的。

如果都将上面的struct改成class,那么B是private继承A的。这就是默认的继承访问权限

public继承还是private继承,取决于子类而不是基类。

struct可以继承class,同样class也可以继承struct,默认的继承访问权限是看子类到底是用的struct还是class

struct A{}class B : A{}; //private继承
struct C : B{}//public继承

要做的更像是一种数据结构的话,那么用struct。要做的更像是一种对象的话,那么用class

struct可以像c一样用大括号直接赋值,如A a={‘p’, 7, 3.1415926}; 但是在struct内部加入一个函数又不能赋值了,class把访问属性改为public也能赋值

虚函数

例子:

一个形状类(类似于框架,部分属性待定,与递归相似)

Untitled

纯虚函数:父类不定义(大部分),留给子类定义(子类必须定义)

虚函数:父类有定义,子类可以重新定义

非虚汗:子类不能定义

继承一般要配合虚函数使用

template mathod

Untitled

面向对象进阶

转换函数(conversion function)

当必要时,c++可以把创建的类自动转换为一个值

class Fraction
{
public:
	Fraction(int num, int den=1)
		: m_numerator(num), m_denominator(den) {  }	
	operator double() const {  // 这里的意思是当需要分数化为double型的时候,编译器可以直接转
		return (double)(m_numerator / m_denomination); 
	}
private:
	int m_numerator; //分子
	int m_denominator;  // 分母
	}
}

调用时

Fraction f(3,5);

Fraction d2 = f+4;// f被自动转换

转换函数要注意不要与构造函数冲突,当冲突的时候可以加在构造函数前加上 explict ,表示只有构造的时候,构造函数才能使用,不要自动转换。

pointer-like classes 智能指针

实例:迭代器

template<class T>
class shared_ptr
{
public:
	T& operator*() cosnt    // 注意c++对于这两种操作符的重载
	{ return *px; }
	T& operator->() cosnt
	{ return px; }
	
	shared_ptr(T* p) : px(p){  }
private:
	T* px;
}

function-like classes 仿函数

重载小括号

struct identity
{
	const T&
	operator() (const T& x) const { return x; } // 括号里的就是参数
};

模板

类模板

调用的时候要用<>指名类型

函数模板

直接调用

成员模板

在模板类里面,又有模板

用于实现下面这种关系

Untitled

模板全特化

//泛华代码
template<class Key>
struct hash {  };
//------------------------------------
//特化
template<>
struct hash<int>{
	sise_t operator()(int x) const { return x; }
	};

类模板偏特化

类型偏特化:

当我们需要指定部分的模板变量的时候,需要偏特化

#include <iostream>
#include <cstring>
using namespace std;

template<typename T, typename T1>
class A {
  public:
    A() = default;
    A(const T1& n) {
        cout << n << endl;
    }
    bool cmp(const T &t1, const T &t2) {
        return t1 == t2;
    }
};

template<typename T1>  // 篇特化
class A<char*, T1> {
  public:
    A() = default;
    A(T1& n) {
        cout << n << endl;
    }
    bool cmp(const char* t1, const char* t2) {
        while(*t1 != '\0' && *t2 != '\0') {
            if(*t1 != *t2) {
                return false;
            }
            ++t1;
            ++t2;
        }
        return true;
    }
};

int main() {
    char* p1 = "hello";
    char* p2 = "hello";
    A<int, char*>c(p1);
    cout << c.cmp(1, 2) << endl;
    A<char*, char*>c1(p2);  // 即使是偏特化,也要全部声明模板
    cout << c1.cmp(p1, p2) << endl;
    return 0;
}

范围偏特化:

template <typename T>
class C {...}; //此泛化版本的T可以是任何类型

template <typename T>
class C<T*> {...}; //特化版本,T为指针类型 将范围缩小

函数在全特化的时候只需要在函数前面加上template<>就行。并且函数又函数重载的概念所以没有偏特化。

模板的模板参数:

当需要一个变化的容器,没有确定传入这个容器的变量类型时用模板的模板

template<typename T,
					template <typename T>
						class SmartPtr
						>
class XCLs
{
private:
	SmartPtr<T> sp;
public:
	XCLs():sp(new T){  }
};

// 调用方式
XCLS<strin, shared_ptr> p1;

注意:这里待定的容器不能有默认参数,当有默认参数再使用模板,会报错,可以用c++2.0来解决

模板参数可变化

将传入的参数分为一个和一包

void print(){
}

template<typename T,typename... Types>
void print(cosnt T& firstArg,cosnt Type&... args)
{
	cout << first << endl;
	print(args...);
}

// sizeof...(args)

auto 语法糖

auto会自己推出类型,必须要在定义的时候就赋值

for循环

for( decl : coll ){ //coll是容器

statement;

}

for (auto i : {1,2,3,4,5,6,7}){ // i为后面的容器的值pass by value
	cout << i << endl;            // 如果要改后面的值 则需要auto&传引用
}

对象模型 虚指针 续表

Untitled

带着虚函数的对象会多一个指针(虚指针),指向虚表。

后面继承的对象可以重写虚函数,改掉虚表的地址位置不变。

动态绑定条件:

1.通过指针调用

2.有向上转型的动作

3.调用虚函数

this

每个成员函数都有的一个this的指针(指向这对象的地址)

执行动态绑定

Untitled

静态绑定与动态绑定

在vs中实际的测试带码和结果如下

#include <iostream>
using namespace std;
class father
{
public:
	virtual void fun1(){
		cout << "father" << endl;
	}
};

class child:
	public father
{
public:
	virtual void fun1() {
		cout << "child" << endl;
	}
};

int main() {
	child c;
	father f;
//	静态绑定
	father f_n = (father)c;
	f_n.fun1();
// 动态绑定
	father* p_f_n = (father *)&c;
	p_f_n->fun1();
//  动态绑定
	father* p_f_n_n = new father;
	p_f_n_n->fun1();
//  动态绑定
	child* p_c_n_n = new child;
	p_c_n_n->fun1();
//  动态绑定
	father& d_c = c;
	d_c.fun1();

	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
一.扑克牌游戏 一副扑克牌去除大小王,剩余52张,A--K,红心,方块,黑桃,梅花四种花色。然后把这一副牌发给两个人,每人分得五张,比较这两人手中牌的大小。 大小的判定规则暂定如下: 牌型比较:同花顺>铁支>葫芦>同花>顺子>三条>二对>对子>散牌。 数字比较:A>K>Q>J>10>9>8 花式比较:黑桃>红桃>草花>方片 牌型说明: 同花顺:拥有五张连续性同花色的顺子。以A为首的同花顺最大。 铁支:四张相同数字的牌,外加一单张。比数字大小,「A」铁支最大 葫芦:由「三条」加一个「对子」所组成的牌,若别家也有此牌型,则比三条数字大小 同花:不构成顺子的五张同花色的牌。先比数字最大的单张,如相同再比第二支、依此类推 顺子:五张连续数字的牌组。 以A为首的顺子最大,如果大家都是顺子,比最大的一张牌,如果大小还一样就比这张牌的花式 三条:牌型由三张相同的牌组成,以A为首的三条最大 二对:牌型中五张牌由两组两张同数字的牌所组成。若遇相同则先比这副牌中最大的一对,如又相同再比第二对,如果还是一样,比大对子中的最大花式 对子:牌型由两张相同的牌加上三张单张所组成。如果大家都是对子,比对子的大小,如果对子也一样,比这个对子中的最大花色 散牌:单一型态的五张散牌所组成,不成对(二对),不成三条,不成顺(同花顺),不成同花,不成葫芦,不成铁支。先比最大一张牌的大小,如果大小一样,比这张牌的花色。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值