Archive for August, 2005

Slicing in C++

Posted on August 8, 2005. Filed under: C/C++ | Tags: , |

Suppose that class D is derived from class C. We can think of D as class C with some extra data and methods. In terms of data, D has all the data that C has, and possible more. In terms of methods, D cannot hide any methods of C, and may have additional methods. In terms of existing methods of C, the only thing that D can do is to override them with its own versions.

If x is an object of class D, then we can slice x with respect to C, by throwing away all of the extensions that made x a D, and keeping only the C part. The result of the slicing is always an object of class C.

Design Principle: Slicing an object with respect to a parent class C should still produce a well-formed object of class C.

Usage Warning: Even though D is-a C, you must be careful. If you have a argument type that is a C and you supply a D it will be sliced if you are doing call by value, pointer, or reference. See the example below.

Note on virtual functions. Their signatures are used to identify which one to execute.

Watch out for the sliced = operator, it can make the lhs inconsistent. Also, the operator= is never virtual, it wouldn’t make sense. For example, suppose classes A, B are both subclasses of class C. Just because an A is a C, and a B is a C, it doesn’t mean you can assign a B object to an A object. Without run-time type information you cannot make a safe assignment.

Usage Warning: If you ever change the size of an object, it and all its base classes must be recompiled! Unless everything is polymorphic and virtual!

13.2 slice.h

 

#ifndef _SLICE_
#define _SLICE_
 
#include <iostream.h>
 
class C {
 
public:
    explicit C(int initial = 0): id(initial), d1(100+initial) {}
    C(const C& arg): id(1000+arg.id), d1(arg.d1) {}
    virtual ~C()    {
        cout << "object " << id << " dying as a C\n";
    }
 
 
    void operator=(const C& rhs) 
    {
        cout << "Object " << id << " doing C =\n";
        Assign(rhs); 
    }
 
    virtual void Assign(const C& rhs) 
    {
        cout << "Assign C\n";
        d1 = rhs.d1;
    }
 
    void Ident() 
    {
        cout << "Object " << id 
            << " thinks it is a C object, d1="
            << d1 << "\n";
    }
 
    virtual void VirtIdent() 
    {
        cout << "Object " << id << 
            " virtually thinks it is a C object, d1="
            << d1 << "\n";
    }
 
protected:
    int id;
    int d1;
};
 
class D: public C {
public:
 
    explicit D(int initial = 0): C(initial), d2(200+initial) {}
    D(const D& arg): C(arg.id), d2(arg.d2) {}
    ~D() 
    {
        cout << "object " << id << " dying as a D\n";
    }
 
    void operator=(const D& rhs) 
    {
        cout << "Object " << id << " doing D =\n";
        Assign(rhs);
    }
 
    void Assign(const D& rhs)
    {
        cout << "Assign in D\n";
        C::Assign(rhs);
        d2 = rhs.d2;
    }
 
    // This version of Ident overrides the parent's, 
    // if we are not sliced!
    void Ident() 
    {
        cout << "Object " << id << 
            " thinks it is a D object, d1=" 
            << d1 << " d2=" << d2 << "\n";
    }
 
    void VirtIdent() 
    {
        cout << "Object " << id << 
            " virtually thinks it is a D object, d1=" 
            << d1 << " d2=" << d2 << "\n";
    }
private:
    int d2;
};
#endi

 

13.3 demo.cpp

 

#include <iostream.h>
#include "slice.h"
 
void SliceIt1(C arg) {
    cout << "Inside SliceIt1: ";
    arg.Ident();
    arg.VirtIdent();
}
 
void SliceIt2(C* arg) {
    cout << "Inside SliceIt2: ";
    (*arg).Ident();
    (*arg).VirtIdent();
}
 
void SliceIt3(C& arg) {
    cout << "Inside SliceIt3: ";
    arg.Ident();
    arg.VirtIdent();
}
 
void CopyIt1(C& x, C& y) {
    cout << "Inside CopyIt1:\n";
    x.Ident(); x.VirtIdent();
    y.Ident(); y.VirtIdent();
    x = y;
    x.Ident(); x.VirtIdent();
}
 
int main(int argc, char* argv[])
{
    D x(1);
    C y(2);
    D z(3);
 
    x.Ident(); x.VirtIdent();
    y.Ident(); y.VirtIdent();
    z.Ident(); z.VirtIdent();
    cout << "\n";
 
    SliceIt1(x); 
    SliceIt1(y);
    cout << "\n";
 
    SliceIt2(&x);
    SliceIt2(&y);
    cout << "\n";
 
    SliceIt3(x);
    SliceIt3(y);
    cout << "\n";
 
    CopyIt1(x, y);  
    // state of x wrong now
    x.VirtIdent();
    x.Ident();
    cout << "\n";
 
    CopyIt1(x, z);
    z.VirtIdent();
    z.Ident();
    cout << "\n";
    return 0;
}

 

13.4 output.txt

 

Object 1 thinks it is a D object, d1=101 d2=201
Object 1 virtually thinks it is a D object, d1=101 d2=201
Object 2 thinks it is a C object, d1=102
Object 2 virtually thinks it is a C object, d1=102
Object 3 thinks it is a D object, d1=103 d2=203
Object 3 virtually thinks it is a D object, d1=103 d2=203
 
Inside SliceIt1: Object 1001 thinks it is a C object, d1=101
Object 1001 virtually thinks it is a C object, d1=101
object 1001 dying as a C
Inside SliceIt1: Object 1002 thinks it is a C object, d1=102
Object 1002 virtually thinks it is a C object, d1=102
object 1002 dying as a C
 
Inside SliceIt2: Object 1 thinks it is a C object, d1=101
Object 1 virtually thinks it is a D object, d1=101 d2=201
Inside SliceIt2: Object 2 thinks it is a C object, d1=102
Object 2 virtually thinks it is a C object, d1=102
 
Inside SliceIt3: Object 1 thinks it is a C object, d1=101
Object 1 virtually thinks it is a D object, d1=101 d2=201
Inside SliceIt3: Object 2 thinks it is a C object, d1=102
Object 2 virtually thinks it is a C object, d1=102
 
Inside CopyIt1:
Object 1 thinks it is a C object, d1=101
Object 1 virtually thinks it is a D object, d1=101 d2=201
Object 2 thinks it is a C object, d1=102
Object 2 virtually thinks it is a C object, d1=102
Object 1 doing C =
Assign C
Object 1 thinks it is a C object, d1=102
Object 1 virtually thinks it is a D object, d1=102 d2=201
Object 1 virtually thinks it is a D object, d1=102 d2=201
Object 1 thinks it is a D object, d1=102 d2=201
 
Inside CopyIt1:
Object 1 thinks it is a C object, d1=102
Object 1 virtually thinks it is a D object, d1=102 d2=201
Object 3 thinks it is a C object, d1=103
Object 3 virtually thinks it is a D object, d1=103 d2=203
Object 1 doing C =
Assign C
Object 1 thinks it is a C object, d1=103
Object 1 virtually thinks it is a D object, d1=103 d2=201
Object 3 virtually thinks it is a D object, d1=103 d2=203
Object 3 thinks it is a D object, d1=103 d2=203
 
object 3 dying as a D
object 3 dying as a C
object 2 dying as a C
object 1 dying as a D
object 1 dying as a C

}

Here is another example:

 
class Shape {
public:
	Shape() { };
	virtual void draw() {};
};

class Circle : public Shape {
private:
	int m_iRadius;
public:
	Circle(int iRadius){ m_iRadius = iRadius; }
	virtual void draw() { /*do drawing*/}
	int GetRadius(){ return m_iRadius; }
};

void funcx(Shape shape) { /*do something*/}

Now, what if we try this:

 
Circle circle(2);
funcx(circle); //Pass a Circle as parameter, when function expects a Shape

Will this result in an error? No. Because Circle is derived from Shape, the compiler will generate a default assignment operator and will copy all the fields common to Circle and Shape. But the m_iRadius field will be lost and there is no way it can be used in funcx.

Another problem is the loss of type information. This may result in undesirable behavior by virtual functions. This phenomenon is called slicing. It is common in exception handling, when exceptions are caught using base class. It is used either to avoid multiple catch blocks or when the types of possible thrown exception is unknown.

 
class CException {};
class CMemoryException : public CException {};
class CFileException: public CException{};

try{ /*do something silly*/ }
catch(CException exception) {/*handle exception*/}

To avoid slicing, change the operations so they use pointer or reference to the base class object rather then the base class object itself. In the given sample code, funcx can be changed so that it takes a pointer/reference to Shape as a parameter rather than Shape:

 
void funcx(Shape *shape) { /*do something*/}

Inside the function body, this pointer can be safely type-casted to a Circle pointer to access Circle specific information:

 
dynamic_cast(shape)->GetRadius();

Reference:
http://webdocs.cs.ualberta.ca/~hoover/Courses/201/201-New-Notes/lectures/section/slice.htm
http://www.devx.com/tips/Tip/14570
Read Full Post | Make a Comment ( None so far )

Administrating a MySQL server

Posted on August 5, 2005. Filed under: Linux, MySQL |

 

Administrating a MySQL server

Setting the password:

1. From Unix:
       shell> mysql -u username -h hostname -p password
       mysql> SET PASSWORD FOR username@localhost=PASSWORD(‘new_password’);

2. Directly manipulate the privilege tables:
       shell> mysql -u username -h host -u username -p
       mysql> UPDATE user SET Password=PASSWORD(‘new_password’) WHERE user=’root’;
       mysql> FLUSH PRIVILEGES;

3. Using the mysqladmin command:
       shell> mysqladmin -u username password new_password

In our case we were able to change password specifying host name along with user name:
       shell> bin/myslqadmin u username h localhost

MySQL Permissions & Grant Tables

In order to add a new user or update user’s privileges in mysql grant tables login to mysql as a root user.

There are two options: use GRANT/REVOKE command or manipulating the MySQL grant tables directly.
The preferred method is to use GRANT statements – more concise and less error-prone.

If you modify the grant tables manually (using INSERT, UPDATE, etc.), you should execute
a FLUSH PRIVILEGES statement to tell the server to reload the grant tables.

To remove user: mysql> delete from user where user=’username’;
        mysql> FLUSH PRIVILEGES;

Examples adding a new user with different level of privileges:
  dummy: A user who can connect without a password, but only from the local host.

       mysql> GRANT USAGE ON *.* TO dummy@localhost;

myUser : A full superuser who can connect to the server from anywhere,
but who must use a password ‘pass’ to do so.
GRANT statements should be for both myUser@localhost and myUser@”%”.
to prevent the anonymous user entry for localhost take precedence.

        mysql> GRANT ALL PRIVILEGES ON *.* TO myUser@localhost
                        IDENTIFIED BY ‘pass’ WITH GRANT OPTION;
       mysql> GRANT ALL PRIVILEGES ON *.* TO myUser@”%”
                        IDENTIFIED BY ‘some_pass’ WITH GRANT OPTION;

      “%” – is a wildcard in mysql. If you are defining your DB table and in the ‘host’ field
enter ‘%’, that means that any host can access that database (Of course, that host
must also have a valid db user).

       admin: A user who can connect from localhost without a password and who is granted
the RELOAD and PROCESS administrative privileges.
No database-related privileges are granted.

          mysql> GRANT RELOAD,PROCESS ON *.* TO admin@localhost;

Add a user that has full rights to his database only but cannot see other database:
           mysql> GRANT USAGE ON *.* TO ‘user’@’host’ GRANT Select, Insert, Update, Delete,
                           Create, Drop ON `database`.* TO ‘user’@’host’ FLUSH PRIVELEGS;

The FILE privelege and WITH GRANT OPTION may not be the best way to include, it is
only in case of creating another superuser with full set of privileges or
giving privileges to load data using mysql command INLOAD DATA.

GRANT TABLE FIELDS EXPLANATION:
TABLE USER: Everything after “password” is a privelege granted with values ‘Y’ or ‘N’.
This table controls individual user global access rights.

‘host’,’user’,’password’,’select’,’insert’,’update’,’delete’,’index’,’alter’
,’create’,’drop’,’grant’,’reload’,’shutdown’,’process’,’file’

TABLE DB: This controls access of USERS to databases.

‘host’,’db’,’user’,’select’,’insert’,’update’,’delete’,’index’,’alter’,
‘create’,’drop’,’grant’

TABLE HOST: This controls which HOSTS are allowed what global access rights.

‘host’,’db’,’select’,’insert’,’update’,’delete’,’index’,’alter’,
‘create’,’drop’,’grant’

HOST, USER, and DB table are very closely connected – if an authorized USER
attempts an SQL request from an unauthorized HOST, it is denied.
If a request from an authorized HOST is not an authorized USER, it is denied.
If a globally authorized USER does not have rights to a certain DB, it is denied.

Backups in MySQL

Full backup of MySql databases:
     1. shell> mysqldump –tab=/path/to/some/dir –opt –full
     OR
     2. shell> mysqlhotcopy database /path/to/some/dir
     OR
     3. simply copy all table files (`*.frm’, `*.MYD’, and `*.MYI’ files)

For a SQL level backup of a table use SELECT INTO OUTFILE or BACKUP TABLE.

           mysql> BACKUP TABLE tbl_name[,tbl_name…] TO ‘/path/to/backup/directory’
Copies to the backup directory the minimum number of table files needed to
restore the table, after flushing any buffered changes to disk.

RESTORE TABLE tbl_name[,tbl_name…] FROM ‘/path/to/backup/directory’
Restores the table(s) from the backup that was made with BACKUP TABLE.
Existing tables will not be overwritten; if you try to restore over an existing
table, you will get an error. Restoring will take longer than backing up due to
the need to rebuild the index. The more keys you have, the longer it will take.
Just as BACKUP TABLE, RESTORE TABLE currently works only for MyISAM tables.

Selective backups can be done with:
              SELECT * INTO OUTFILE ‘file_name’ FROM tbl_name
and restore with:
              LOAD DATA INFILE ‘file_name’ REPLACE …
To avoid duplicate records, you need a PRIMARY KEY or a UNIQUE key in the table.
The REPLACE keyword causes old records to be replaced with new ones when a new
record duplicates an old record on a unique key value.

Monitoring tools

The myisamchk utility is used to get information, check, repair or optimise mysql database tables:
              shell> myisamchk [options] tbl_name

With no options, myisamchk simply checks the table.

Some useful Options for myisamchk utility:

1. Print informational statistics about the table that is checked: -i or –information
2. Check only tables that have changed since the last check: -C or –check-only-changed
3. The recommended way to quickly check all tables:
              myisamchk –silent –fast /path/to/datadir/*/*.MYI

To Start the server automatically at system startup time

The mysql.server and safe_mysqld scripts can be used to start/stop the server automatically.
        shell> mysql.server start
        shell> mysql.server stop

See mysql.server in the `share/mysql’ directory or in the `support-files’ directory of the MySQL source tree.
The mysql.server script understands the following options: datadir, basedir, and pid-file.

If your system uses `/etc/rc.local’ to start external scripts, you should append the following to it:

     /bin/sh -c ‘cd /usr/local/mysql ; ./bin/safe_mysqld –user=mysql &’

The mysql.server script understands the following options: datadir, basedir, and pid-file.

Reference:
http://www-css.fnal.gov/dsg/external/freeware/mysqlAdmin.html

Read Full Post | Make a Comment ( None so far )

Liked it here?
Why not try sites on the blogroll...