1/21
Bài 12
CÁC KHÁI NIỆM NÂNG CAO
VỀ CLASS
Hàm friend
2/21
Để một hàm không phải thành viên truy xuất được
các thành viên riêng của lớp phải khai báo bằng từ
khóa friend.
Cần khai báo prototype của hàm bạn trong phần
public của class. Ví dụ
class cl {
//
public:
friend void frnd(cl ob);
//
};
3/21
class myclass {
int a, b;
public:
myclass(int i, int j) { a=i; b=j; }
friend int sum(myclass x); // sum() is a friend of myclass
};
int sum(myclass x)
{
return x.a + x.b;
}
int main()
{
myclass n(3, 4);
cout << sum(n);
return 0;
}
Ví dụ
Quá tải constructor
4/21
Dùng hàm tạo ở những dạng khác.
Để quá tải hàm tạo chỉ việc khai báo dạng mà nó
nhận và định nghĩa mỗi hành động liên hệ với
những dạng này.
Ví dụ
5/21
#include <ctime>
class timer{
int seconds;
public:
// seconds specified as a string
timer(char *t) { seconds = atoi(t); }
// seconds specified as integer
timer(int t) { seconds = t; }
// time specified in minutes and seconds
timer(int min, int sec) { seconds = min*60 + sec; }
void run();
} ;
void timer::run()
{
clock_t t1;
t1 = clock();
while((clock()/CLOCKS_PER_SEC - t1/CLOCKS_PER_SEC) <
seconds);
cout << "\a"; // ring the bell
}
int main()
{
timer a(10), b("20"), c(1, 10);
a.run(); // count 10 seconds
b.run(); // count 20 seconds
c.run(); // count 1 minute, 10 seconds
return 0;
}
Từ khóa this
6/21
Mỗi khi một hàm thành viên được gọi nó được
truyền một con trỏ chỉ đến đối tượng gọi hàm.
Con trỏ this là một tham số không tường minh đối
với tất cả các hàm thành viên, vì vậy trong hàm
thành viên this có thể được dùng để tham chiếu đến
đối tượng gọi nó.
class cl {
int i;
void f() { };
//
};
Bên trong f( ), câu lệnh gán cho i giá trị 10:
i = 10;
Thực ra câu lệnh trên là viết tắt của :
this->i = 10;
7/21
#include <iostream>
using namespace std;
class cl {
int i;
public:
void load_i(int val) { this->i = val; } // same as i = val
int get_i() { return this->i; } // same as return i
} ;
int main()
{
cl o;
o.load_i(100);
cout << o.get_i();
return 0;
}
Quá tải toán tử
8/21
C++ cho phép quá tải toán tử liên hệ với các kiểu class.
Quá tải toán tử cho phép định nghĩa ý nghĩa của một
toán tử cho một class đặc biệt.
Ví dụ một class định nghĩa một danh sách liên kết có
thể dùng toán tử + để thêm một đối tượng vào danh
sách.
Quá tải một toán tử chỉ đơn giản là định nghĩa một toán
tử mới liên hệ với một class mà không làm thay đổi ý
nghĩa gốc của một toán tử.
9/21
Để quá tải một toán tử cần định nghĩa ý nghĩa
nào của toán tử liên hệ với class. Tạo một hàm
operator, định nghĩa hành vi của toán tử
Dạng tổng quát
Kiểu Tên lớp::operator Toán tử(Danh sách
tham số)
{
Hành vi liên hệ với class
}
10/21
#include <iostream>
using namespace std;
class three_d {
int x, y, z; // 3-D coordinates
public:
three_d() { x = y = z = 0; }
three_d(int i, int j, int k) {x = i; y = j; z = k; }
three_d operator+(three_d op2); // op1 ẩn
three_d operator=(three_d op2); // op1ẩn
void show() ;
};
// Quá tải +.
three_d three_d::operator+(three_d op2)
{
three_d temp;
temp.x = x + op2.x; //x chính là this->x
temp.y = y + op2.y;
temp.z = z + op2.z;
return temp;
}
// Quá tải phép gán.
three_d three_d::operator=(three_d op2)
{
x = op2.x;
y = op2.y;
z = op2.z;
return *this;//trả về đối tượng được trỏ bởi this
}
void three_d::show()
{
cout << x << ", ";
cout << y << ", ";
cout << z << "\n";
}
11/21
int main()
{
three_d a(1, 2, 3), b(10, 10, 10), c;
a.show();
b.show();
c = a + b; // cộng a với b r
c.show();
c = a + b + c; // cộng a, b và c
c.show();
c = b = a; // gán liên tiếp
c.show();
b.show();
return 0;
}
Tính thừa kế
12/21
C++ hỗ trợ tính thừa kế bằng cách cho phép một
class hợp nhất với class khác trong khai báo.
Khai báo:
class Tên class nhận thừa kế : Tên class cho
thừa kế {
Thân class nhận thừa kế
}
13/21
class xe {
int banh;
int nguoi;
public:
void set_banh(int num) { banh = num; }
int get_banh() { return banh; }
void set_ng(int num) { nguoi = num; }
int get_ng() { return nguoi; }
};
class xe_tai : public xe {
int hanghoa;
public:
void set_hanghoa(int size) { hanghoa = size; }
int get_hanghoa() { return hanghoa; }
void show();
};
14/21
#include <iostream>
using namespace std;
// Define a base class for vehicles.
class road_vehicle {
int wheels;
int passengers;
public:
void set_wheels(int num) { wheels = num; }
int get_wheels() { return wheels; }
void set_pass(int num) { passengers = num; }
int get_pass() { return passengers; }
};
// Define a truck.
class truck : public road_vehicle {
int cargo;
public:
void set_cargo(int size) { cargo = size; }
int get_cargo() { return cargo; }
void show();
};
enum type {car, van, wagon};
// Define an automoble.
class automobile : public road_vehicle {
enum type car_type;
public:
void set_type(type t) { car_type = t; }
enum type get_type() { return car_type; }
void show();
};
void truck::show()
{
cout << "wheels: " << get_wheels() << "\n";
cout << "passengers: " << get_pass() << "\n";
cout << "cargo capacity in cubic feet: " <<
cargo << "\n";
}
15/21
void automobile::show()
{
cout << "wheels: " << get_wheels() << "\n";
cout << "passengers: " << get_pass() << "\n";
cout << "type: ";
switch(get_type()) {
case van: cout << "van\n";
break;
case car: cout << "car\n";
break;
case wagon: cout << "wagon\n";
}
}
int main()
{
truck t1, t2;
automobile c;
t1.set_wheels(18);
t1.set_pass(2);
t1.set_cargo(3200);
t2.set_wheels(6);
t2.set_pass(3);
t2.set_cargo(1200);
t1.show();
cout << "\n";
t2.show();
cout << "\n";
c.set_wheels(4);
c.set_pass(6);
c.set_type(van);
c.show();
return 0;
}
Dùng thành viên được bảo vệ
16/21
Ngoài private, public, thành viên của class còn
được khai báo là protected
Dùng protected có thể tạo các thành viên của
class là private đối với class của chúng nhưng
vẫn được thừa kế và được truy xuất bởi các lớp
nhận thừa kế
17/21
#include <iostream>
using namespace std;
class base {
protected:
int i, j; // private đối với base, nhưng có thể
//được truy xuất với derived
public:
void set(int a, int b) { i = a; j = b; }
void show() { cout << i << " " << j <<
"\n"; }
};
class derived : public base {
int k;
public:
// derived có thể truy xuất i và j của base
void setk() { k = i*j; }
void showk() { cout << k << "\n"; }
};
int main()
{
derived ob;
ob.set(2, 3); // derived hiểu và dùng
ob.show(); // derived hiểu và dùng
ob.setk();
ob.showk();
return 0;
}
Đa hình
18/21
Đa hình là thuật ngữ mô tả một quá trình trong đó
các hiện thực khác nhau của hàm có thể được
truy xuất qua cùng một tên.
"Một giao tiếp, Đa phương thức"
Các con trỏ chỉ đến các kiểu thừa kế
Con trỏ lớp cơ sở và con trỏ lớp thừa kế được liên
hệ với nhau.
19/21
class B_class {
char author[80];
public:
void put_author(char *s) { strcpy(author, s); }
void show_author() { cout << author << "\n"; }
} ;
class D_class : public B_class {
char title[80];
public:
void put_title(char *num) {
strcpy(title, num);
}
void show_title() {
cout << "Title: ";
cout << title << "\n";
}
};
{
B_class *p;
B_class B_ob;
D_class *dp;
D_class D_ob;
p = &B_ob; // địa chỉ của base
// truy xuất B_class qua pointer.
p->put_author("Tom Clancy");
// truy xuất D_class qua base pointer.
p = &D_ob;
p->put_author("William Shakespeare");
// Mỗi author vào một đối tượng thích hợp
B_ob.show_author();
D_ob.show_author();
cout << "\n";
dp = &D_ob;
dp->put_title("The Tempest");
p->show_author(); // p hoặc dp có thể được
//dùng ở đây.
dp->show_title( );
return 0;
}
20/21
Hàm ảo: Hàm ảo là một hàm được khai báo bằng
từ khóa virtual trong một lớp cơ sở và được định
nghĩa lại trong một hay nhiều lớp thừa kế.
21/21
class base {
public:
virtual void who() { // chỉ ra một virtual
cout << "Base\n";
}
};
class first_d : public base {
public:
void who() { // định nghĩa lại who() quan hệ
//với first_d
cout << "First derivation\n";
}
};
class second_d : public base {
public:
void who() { // định nghĩa lại who() quan hệ
//second_d
cout << "Second derivation\n";
}
};
first_d first_obj;
second_d second_obj;
p = &base_obj;
p->who(); // truy xuất who của base
p = &first_obj;
p->who(); // truy xuất who của first_d
p = &second_obj;
p->who(); // truy xuất who của second_d
return 0;
}